using System;
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using dnAnalytics.Math;
using dnAnalytics.LinearAlgebra;
using dnAnalytics.Exceptions;

namespace dnAnalytics.UnitTests.LinearAlgebra
{
    public abstract class AbstractMatrixTest// : AbstractTest
    {
        protected static readonly double[] testArray = new double[] { -1.1, -2.2, -3.3, 0, 1.1, 2.2 };
        protected static readonly double[,] square = new double[,] { { -1.1, -2.2, -3.3 }, { 0, 1.1, 2.2 }, { -4.4, 5.5, 6.6 } };
        protected static readonly double[,] singular = new double[,] { { 1, 1, 2 }, { 1, 1, 2 }, { 1, 1, 2 } };
        protected static readonly double[,] wide = new double[,] { { -1.1, -2.2, -3.3 }, { 0, 1.1, 2.2 } };
        protected static readonly double[,] tall = new double[,] { { -1.1, -2.2 }, { 0, 1.1 }, { -4.4, 5.5 } };

        protected const int m = 4;
        protected const int n = 3;

        public abstract Matrix GetMatrix(int order);
        public abstract Matrix GetMatrix(int m, int n);
        public abstract Matrix GetMatrix(double[,] data);
        public abstract Vector GetVector(int size);
        public abstract Vector GetVector(double[] data);

        [Test]
        public void AddScalar()
        {
            Matrix matrix = GetMatrix(square);
            matrix.Add(2.2);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] + 2.2, matrix[i, j]);
                }
            }

            matrix = GetMatrix(wide);
            matrix.Add(2.2);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] + 2.2, matrix[i, j]);
                }
            }

            matrix = GetMatrix(tall);
            matrix.Add(2.2);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] + 2.2, matrix[i, j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AddScalarResultNull()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = null;
            matrix.Add(2.2, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void AddScalarResultNotConformable1()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = GetMatrix(matrix.Rows + 1, matrix.Columns);
            matrix.Add(2.2, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void AddScalarResultNotConformable2()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = GetMatrix(matrix.Rows, matrix.Columns + 1);
            matrix.Add(2.2, result);
        }

        [Test]
        public void AddMatrix()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = matrix.Clone();
            matrix.Add(other);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] + square[i, j], matrix[i, j]);
                }
            }

            matrix = GetMatrix(wide);
            other = matrix.Clone();
            matrix.Add(other);

            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(wide[i, j] + wide[i, j], matrix[i, j]);
                }
            }

            matrix = GetMatrix(tall);
            other = matrix.Clone();
            matrix.Add(other);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(tall[i, j] + tall[i, j], matrix[i, j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AddMatrixNull()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = null;
            matrix.Add(other);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void AddMatrixNotConformable1()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = GetMatrix(matrix.Rows + 1, matrix.Columns);
            matrix.Add(other);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void AddMatrixNotConformable2()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = GetMatrix(matrix.Rows, matrix.Columns + 1);
            matrix.Add(other);
        }

        [Test]
        public void AddMatrixResult()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = matrix.Clone();
            Matrix result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Add(other, result);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] + square[i, j], result[i, j]);
                }
            }

            matrix = GetMatrix(wide);
            other = matrix.Clone();
            result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Add(other, result);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(wide[i, j] + wide[i, j], result[i, j]);
                }
            }

            matrix = GetMatrix(tall);
            other = matrix.Clone();
            result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Add(other, result);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(tall[i, j] + tall[i, j], result[i, j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AddMatrixResultNull1()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = null;
            Matrix result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Add(other, result);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AddMatrixResultNull2()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = matrix.Clone();
            Matrix result = null;
            matrix.Add(other, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void AddMatrixResultNotConformable1()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = GetMatrix(matrix.Rows + 1, matrix.Columns);
            Matrix result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Add(other, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void AddMatrixResultNotConformable2()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = GetMatrix(matrix.Rows, matrix.Columns + 1);
            Matrix result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Add(other, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void AddMatrixResultNotConformable3()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = GetMatrix(matrix.Rows, matrix.Columns);
            Matrix result = GetMatrix(matrix.Rows + 1, matrix.Columns);
            matrix.Add(other, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void AddMatrixResultNotConformable4()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = GetMatrix(matrix.Rows, matrix.Columns);
            Matrix result = GetMatrix(matrix.Rows, matrix.Columns + 1);
            matrix.Add(other, result);
        }

        [Test]
        public void Append()
        {
            Matrix left = GetMatrix(square);
            Matrix right = GetMatrix(tall);
            Matrix result = left.Append(right);
            Assert.AreEqual(left.Columns + right.Columns, result.Columns);
            Assert.AreEqual(left.Rows, right.Rows);

            for (int i = 0; i < result.Rows; i++)
            {
                for (int j = 0; j < result.Columns; j++)
                {
                    if (j < left.Columns)
                    {
                        Assert.AreEqual(left[i, j], result[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(right[i, j - left.Columns], result[i, j]);
                    }
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AppendNull()
        {
            Matrix left = GetMatrix(square);
            Matrix right = null;
            Matrix result = left.Append(right);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void AppendNotConformable()
        {
            Matrix left = GetMatrix(wide);
            Matrix right = GetMatrix(tall);
            Matrix result = left.Append(right);
        }

        [Test]
        public void AppendResult()
        {
            Matrix left = GetMatrix(square);
            Matrix right = GetMatrix(tall);
            Matrix result = GetMatrix(left.Rows, left.Columns + right.Columns);
            left.Append(right, result);
            Assert.AreEqual(left.Columns + right.Columns, result.Columns);
            Assert.AreEqual(left.Rows, right.Rows);

            for (int i = 0; i < result.Rows; i++)
            {
                for (int j = 0; j < result.Columns; j++)
                {
                    if (j < left.Columns)
                    {
                        Assert.AreEqual(left[i, j], result[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(right[i, j - left.Columns], result[i, j]);
                    }
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AppendResultNull1()
        {
            Matrix left = GetMatrix(square);
            Matrix right = null;
            Matrix result = GetMatrix(left.Rows + left.Rows, left.Columns);
            left.Append(right, result);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AppendResultNull2()
        {
            Matrix left = GetMatrix(square);
            Matrix right = GetMatrix(tall);
            Matrix result = null;
            left.Append(right, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void AppendResultNotConformable1()
        {
            Matrix left = GetMatrix(wide);
            Matrix right = GetMatrix(tall);
            Matrix result = GetMatrix(left.Columns + right.Columns, left.Columns);
            left.Append(right, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void AppendResultNotConformable2()
        {
            Matrix left = GetMatrix(wide);
            Matrix right = GetMatrix(wide);
            Matrix result = GetMatrix(left.Columns + right.Columns + 1, left.Columns);
            left.Append(right, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void AppendResultNotConformable3()
        {
            Matrix left = GetMatrix(wide);
            Matrix right = GetMatrix(wide);
            Matrix result = GetMatrix(left.Columns + right.Columns, left.Columns + 1);
            left.Append(right, result);
        }

        [Test]
        public void Clear()
        {
            Matrix matrix = GetMatrix(square);
            matrix.Clear();
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(0, matrix[i, j]);
                }
            }
        }

        [Test]
        public void Clone()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = matrix.Clone();
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j], matrix[i, j]);
                    Assert.AreEqual(matrix[i, j], other[i, j]);
                }
            }
        }

        [Test]
        public void Column()
        {
            Matrix matrix = GetMatrix(square);
            for (int i = 0; i < matrix.Columns; i++)
            {
                Vector column = matrix.Column(i);
                Assert.AreEqual(matrix.Rows, column.Count);
                for (int j = 0; j < matrix.Rows; j++)
                {
                    Assert.AreEqual(matrix[j, i], column[j]);
                }
            }

            matrix = GetMatrix(wide);
            for (int i = 0; i < matrix.Columns; i++)
            {
                Vector column = matrix.Column(i);
                Assert.AreEqual(matrix.Rows, column.Count);
                for (int j = 0; j < matrix.Rows; j++)
                {
                    Assert.AreEqual(matrix[j, i], column[j]);
                }
            }

            matrix = GetMatrix(tall);
            for (int i = 0; i < matrix.Columns; i++)
            {
                Vector column = matrix.Column(i);
                Assert.AreEqual(matrix.Rows, column.Count);
                for (int j = 0; j < matrix.Rows; j++)
                {
                    Assert.AreEqual(matrix[j, i], column[j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void ColumnArgumentOutOfRange1()
        {
            Matrix matrix = GetMatrix(square);
            Vector column = matrix.Column(-1);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void ColumnArgumentOutOfRange2()
        {
            Matrix matrix = GetMatrix(square);
            Vector column = matrix.Column(matrix.Columns);
        }

        [Test]
        public void ColumnResult()
        {
            Matrix matrix = GetMatrix(square);
            for (int i = 0; i < matrix.Columns; i++)
            {
                Vector column = GetVector(matrix.Rows);
                matrix.Column(i, column);
                for (int j = 0; j < matrix.Rows; j++)
                {
                    Assert.AreEqual(matrix[j, i], column[j]);
                }
            }

            matrix = GetMatrix(wide);
            for (int i = 0; i < matrix.Columns; i++)
            {
                Vector column = GetVector(matrix.Rows);
                matrix.Column(i, column);
                for (int j = 0; j < matrix.Rows; j++)
                {
                    Assert.AreEqual(matrix[j, i], column[j]);
                }
            }

            matrix = GetMatrix(tall);
            for (int i = 0; i < matrix.Columns; i++)
            {
                Vector column = GetVector(matrix.Rows);
                matrix.Column(i, column);
                for (int j = 0; j < matrix.Rows; j++)
                {
                    Assert.AreEqual(matrix[j, i], column[j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void ColumnResultNull()
        {
            Matrix matrix = GetMatrix(square);
            Vector column = null;
            matrix.Column(0, column);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void ColumnResultArgumentOutOfRange1()
        {
            Matrix matrix = GetMatrix(square);
            Vector column = GetVector(matrix.Rows);
            matrix.Column(-1, column);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void ColumnResultArgumentOutOfRange2()
        {
            Matrix matrix = GetMatrix(square);
            Vector column = GetVector(matrix.Rows);
            matrix.Column(matrix.Columns, column);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void ColumnResultNotConformable()
        {
            Matrix matrix = GetMatrix(square);
            Vector column = GetVector(matrix.Rows + 1);
            matrix.Column(0, column);
        }

        [Test]
        public void ColumnRange()
        {
            Matrix matrix = GetMatrix(square);
            Range range = new Range(0, matrix.Rows - 1, 2);
            for (int i = 0; i < matrix.Columns; i++)
            {
                Vector column = matrix.Column(i, range);
                Assert.AreEqual((range.End - range.Start) / range.Stride + 1, column.Count);
                for (int j = range.Start, k = 0; j <= range.End; j += range.Stride, k++)
                {
                    Assert.AreEqual(matrix[j, i], column[k]);
                }
            }

            matrix = GetMatrix(wide);
            range = new Range(0, matrix.Rows - 1, 2);
            for (int i = 0; i < matrix.Columns; i++)
            {
                Vector column = matrix.Column(i, range);
                Assert.AreEqual((range.End - range.Start) / range.Stride + 1, column.Count);
                for (int j = range.Start, k = 0; j <= range.End; j += range.Stride, k++)
                {
                    Assert.AreEqual(matrix[j, i], column[k]);
                }
            }

            matrix = GetMatrix(tall);
            range = new Range(0, matrix.Rows - 1, 2);
            for (int i = 0; i < matrix.Columns; i++)
            {
                Vector column = matrix.Column(i, range);
                Assert.AreEqual((range.End - range.Start) / range.Stride + 1, column.Count);
                for (int j = range.Start, k = 0; j <= range.End; j += range.Stride, k++)
                {
                    Assert.AreEqual(matrix[j, i], column[k]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void ColumnIndexArgumentOutOfRange1()
        {
            Matrix matrix = GetMatrix(square);
            Range range = new Range(0, matrix.Rows - 1);
            Vector column = matrix.Column(-1, range);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void ColumnIndexArgumentOutOfRange2()
        {
            Matrix matrix = GetMatrix(square);
            Range range = new Range(0, matrix.Rows - 1);
            Vector column = matrix.Column(matrix.Columns, range);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void ColumnRangeArgumentOutOfRange1()
        {
            Matrix matrix = GetMatrix(square);
            Range range = new Range(0, matrix.Rows);
            Vector column = matrix.Column(0, range);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void ColumnRangeArgumentOutOfRange2()
        {
            Matrix matrix = GetMatrix(square);
            Range range = new Range(matrix.Rows, matrix.Rows + 1);
            Vector column = matrix.Column(0, range);
        }

        [Test]
        public void ColumnEnumerator()
        {
            Matrix matrix = GetMatrix(square);
            foreach (KeyValuePair<int, Vector> column in matrix.ColumnEnumerator())
            {
                foreach (KeyValuePair<int, double> value in column.Value)
                {
                    Assert.AreEqual(matrix[value.Key, column.Key], value.Value);
                }
            }


            matrix = GetMatrix(wide);
            foreach (KeyValuePair<int, Vector> column in matrix.ColumnEnumerator())
            {
                foreach (KeyValuePair<int, double> value in column.Value)
                {
                    Assert.AreEqual(matrix[value.Key, column.Key], value.Value);
                }
            }

            matrix = GetMatrix(tall);
            foreach (KeyValuePair<int, Vector> column in matrix.ColumnEnumerator())
            {
                foreach (KeyValuePair<int, double> value in column.Value)
                {
                    Assert.AreEqual(matrix[value.Key, column.Key], value.Value);
                }
            }
        }

        [Test]
        public void ColumnEnumeratorRange()
        {
            Matrix matrix = GetMatrix(square);
            Range range = new Range(0, matrix.Columns - 1, 2);
            foreach (KeyValuePair<int, Vector> column in matrix.ColumnEnumerator(range))
            {
                foreach (KeyValuePair<int, double> value in column.Value)
                {
                    Assert.AreEqual(matrix[value.Key, column.Key], value.Value);
                }
            }

            matrix = GetMatrix(wide);
            range = new Range(0, matrix.Columns - 1, 2); 
            foreach (KeyValuePair<int, Vector> column in matrix.ColumnEnumerator(range))
            {
                foreach (KeyValuePair<int, double> value in column.Value)
                {
                    Assert.AreEqual(matrix[value.Key, column.Key], value.Value);
                }
            }

            matrix = GetMatrix(tall);
            range = new Range(0, matrix.Columns - 1, 2);            
            foreach (KeyValuePair<int, Vector> column in matrix.ColumnEnumerator(range))
            {
                foreach (KeyValuePair<int, double> value in column.Value)
                {
                    Assert.AreEqual(matrix[value.Key, column.Key], value.Value);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void ColumnEnumeratorRangeArgumentOutOfRange1()
        {
            Matrix matrix = GetMatrix(square);
            Range range = new Range(matrix.Columns, matrix.Columns + 1);
            foreach (KeyValuePair<int, Vector> column in matrix.ColumnEnumerator(range)) { }
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void ColumnEnumeratorRangeArgumentOutOfRange2()
        {
            Matrix matrix = GetMatrix(square);
            Range range = new Range(0, matrix.Columns + 1);
            foreach (KeyValuePair<int, Vector> column in matrix.ColumnEnumerator(range)) { }
        }

        [Test]
        public void RowsColumns()
        {
            Matrix matrix = GetMatrix(m, n);
            Assert.AreEqual(m, matrix.Rows);
            Assert.AreEqual(n, matrix.Columns);
        }

        [Test]
        public void ConditionNumber()
        {
            Matrix matrix = GetMatrix(square);
            double conditionNumber = matrix.ConditionNumber();
            Assert.AreEqual(28.771263047452674, conditionNumber, Constants.ACCEPTABLE_ERROR);

            matrix = GetMatrix(wide);
            conditionNumber = matrix.ConditionNumber();
            Assert.AreEqual(7.62557995205955, conditionNumber, Constants.ACCEPTABLE_ERROR);

            matrix = GetMatrix(tall);
            conditionNumber = matrix.ConditionNumber();
            Assert.AreEqual(3.12634485713208, conditionNumber, Constants.ACCEPTABLE_ERROR);
        }
        [Test]
        public void CopyTo()
        {
            Matrix matrix = GetMatrix(square);
            Matrix target = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.CopyTo(target);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], target[i, j]);
                }
            }

            matrix = GetMatrix(wide);
            target = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.CopyTo(target);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], target[i, j]);
                }
            }

            matrix = GetMatrix(tall);
            target = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.CopyTo(target);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], target[i, j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CopyToNull()
        {
            Matrix matrix = GetMatrix(square);
            Matrix target = null;
            matrix.CopyTo(target);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void CopyToNotConformableException()
        {
            Matrix matrix = GetMatrix(wide);
            Matrix target = GetMatrix(matrix.Columns, matrix.Rows);
            matrix.CopyTo(target);
        }

        [Test]
        public void Determinant()
        {
            Matrix matrix = GetMatrix(square);
            double det = matrix.Determinant();
            Assert.AreEqual(10.648, det, Constants.ACCEPTABLE_ERROR);
        }

        [Test]
        [ExpectedException(typeof(NotSquareMatrixException))]
        public void DeterminantNotSquareMatrix()
        {
            Matrix matrix = GetMatrix(wide);
            double det = matrix.Determinant();
        }

        [Test]
        public void Diagonal()
        {
            Matrix matrix = GetMatrix(square);
            Vector vector = matrix.Diagonal();
            int size = System.Math.Min(matrix.Rows, matrix.Columns);
            Assert.AreEqual(size, vector.Count);
            for (int i = 0; i < size; i++)
            {
                Assert.AreEqual(matrix[i, i], vector[i]);
            }

            matrix = GetMatrix(wide);
            vector = matrix.Diagonal();
            size = System.Math.Min(matrix.Rows, matrix.Columns);
            Assert.AreEqual(size, vector.Count);
            for (int i = 0; i < size; i++)
            {
                Assert.AreEqual(matrix[i, i], vector[i]);
            }

            matrix = GetMatrix(tall);
            vector = matrix.Diagonal();
            size = System.Math.Min(matrix.Rows, matrix.Columns);
            Assert.AreEqual(size, vector.Count);
            for (int i = 0; i < size; i++)
            {
                Assert.AreEqual(matrix[i, i], vector[i]);
            }
        }

        [Test]
        public void DiagonalResult()
        {
            Matrix matrix = GetMatrix(square);
            int size = System.Math.Min(matrix.Rows, matrix.Columns);
            Vector vector = GetVector(size);
            matrix.Diagonal(vector);
            for (int i = 0; i < size; i++)
            {
                Assert.AreEqual(matrix[i, i], vector[i]);
            }

            matrix = GetMatrix(wide);
            size = System.Math.Min(matrix.Rows, matrix.Columns);
            vector = GetVector(size);
            matrix.Diagonal(vector);
            for (int i = 0; i < size; i++)
            {
                Assert.AreEqual(matrix[i, i], vector[i]);
            }

            matrix = GetMatrix(tall);
            size = System.Math.Min(matrix.Rows, matrix.Columns);
            vector = GetVector(size);
            matrix.Diagonal(vector);
            for (int i = 0; i < size; i++)
            {
                Assert.AreEqual(matrix[i, i], vector[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void DiagonalResultNull()
        {
            Matrix matrix = GetMatrix(square);
            Vector vector = null;
            matrix.Diagonal(vector);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void DiagonalResultNotConformable()
        {
            Matrix matrix = GetMatrix(square);
            Vector vector = GetVector(matrix.Rows + 1);
            matrix.Diagonal(vector);
        }

        [Test]
        public void DiagonalStack()
        {
            Matrix top = GetMatrix(tall);
            Matrix bottom = GetMatrix(wide);
            Matrix result = top.DiagonalStack(bottom);
            Assert.AreEqual(top.Rows + bottom.Rows, result.Rows);
            Assert.AreEqual(top.Columns + bottom.Columns, result.Columns);

            for (int i = 0; i < result.Rows; i++)
            {
                for (int j = 0; j < result.Columns; j++)
                {
                    if (i < top.Rows && j < top.Columns)
                    {
                        Assert.AreEqual(top[i, j], result[i, j]);
                    }
                    else if (i >= top.Rows && j >= top.Columns)
                    {
                        Assert.AreEqual(bottom[i - top.Rows, j - top.Columns], result[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, result[i, j]);
                    }
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void DiagonalStackNull()
        {
            Matrix top = GetMatrix(square);
            Matrix bottom = null;
            top.DiagonalStack(bottom);
        }

        [Test]
        public void DiagonalStackResult()
        {
            Matrix top = GetMatrix(tall);
            Matrix bottom = GetMatrix(wide);
            Matrix result = GetMatrix(top.Rows + bottom.Rows, top.Columns + bottom.Columns);
            top.DiagonalStack(bottom, result);

            for (int i = 0; i < result.Rows; i++)
            {
                for (int j = 0; j < result.Columns; j++)
                {
                    if (i < top.Rows && j < top.Columns)
                    {
                        Assert.AreEqual(top[i, j], result[i, j]);
                    }
                    else if (i >= top.Rows && j >= top.Columns)
                    {
                        Assert.AreEqual(bottom[i - top.Rows, j - top.Columns], result[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, result[i, j]);
                    }
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void DiagonalStackResultNull1()
        {
            Matrix top = GetMatrix(square);
            Matrix bottom = null;
            Matrix result = GetMatrix(top.Rows + top.Rows, top.Columns + top.Columns);
            top.DiagonalStack(bottom, result);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void DiagonalStackResultNull2()
        {
            Matrix top = GetMatrix(square);
            Matrix bottom = GetMatrix(square);
            Matrix result = null;
            top.DiagonalStack(bottom, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void DiagonalStackResultNotConformableException1()
        {
            Matrix top = GetMatrix(square);
            Matrix bottom = GetMatrix(square); ;
            Matrix result = GetMatrix(top.Rows + bottom.Rows + 1, top.Columns + bottom.Columns);
            top.DiagonalStack(bottom, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void DiagonalStackResultNotConformableException2()
        {
            Matrix top = GetMatrix(square);
            Matrix bottom = GetMatrix(square); ;
            Matrix result = GetMatrix(top.Rows + bottom.Rows, top.Columns + bottom.Columns + 1);
            top.DiagonalStack(bottom, result);
        }

        [Test]
        public void Divide()
        {
            Matrix matrix = GetMatrix(square);
            matrix.Divide(2.3);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] / 2.3, matrix[i, j], Constants.ACCEPTABLE_ERROR);
                }
            }

            matrix = GetMatrix(wide);
            matrix.Divide(2.3);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(wide[i, j] / 2.3, matrix[i, j], Constants.ACCEPTABLE_ERROR);
                }
            }

            matrix = GetMatrix(tall);
            matrix.Divide(2.3);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(tall[i, j] / 2.3, matrix[i, j], Constants.ACCEPTABLE_ERROR);
                }
            }
        }

        [Test]
        public void DivideResult()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Divide(2.3, result);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] / 2.3, result[i, j], Constants.ACCEPTABLE_ERROR);
                }
            }

            matrix = GetMatrix(wide);
            result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Divide(2.3, result);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(wide[i, j] / 2.3, result[i, j], Constants.ACCEPTABLE_ERROR);
                }
            }

            matrix = GetMatrix(tall);
            result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Divide(2.3, result);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(tall[i, j] / 2.3, result[i, j], Constants.ACCEPTABLE_ERROR);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void DivideResultNull()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = null;
            matrix.Divide(2.3, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void DivideResultNotConformable1()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = GetMatrix(matrix.Rows + 1, matrix.Columns);
            matrix.Divide(2.3, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void DivideResultNotConformable2()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = GetMatrix(matrix.Rows, matrix.Columns + 1);
            matrix.Divide(2.3, result);
        }

        [Test]
        public void FrobeniusNorm()
        {
            Matrix matrix = GetMatrix(square);
            Assert.AreEqual(10.77775486824598, matrix.FrobeniusNorm(), Constants.ACCEPTABLE_ERROR);

            matrix = GetMatrix(wide);
            Assert.AreEqual(4.79478883789474, matrix.FrobeniusNorm(), Constants.ACCEPTABLE_ERROR);

            matrix = GetMatrix(tall);
            Assert.AreEqual(7.54122006044115, matrix.FrobeniusNorm(), Constants.ACCEPTABLE_ERROR);
        }

        [Test]
        public void InfinityNorm()
        {
            Matrix matrix = GetMatrix(square);
            Assert.AreEqual(16.5, matrix.InfinityNorm());

            matrix = GetMatrix(wide);
            Assert.AreEqual(6.6, matrix.InfinityNorm());

            matrix = GetMatrix(tall);
            Assert.AreEqual(9.9, matrix.InfinityNorm());
        }

        [Test]
        public void L1Norm()
        {
            Matrix matrix = GetMatrix(square);
            Assert.AreEqual(12.1, matrix.L1Norm());

            matrix = GetMatrix(wide);
            Assert.AreEqual(5.5, matrix.L1Norm());

            matrix = GetMatrix(tall);
            Assert.AreEqual(8.8, matrix.L1Norm());
        }

        [Test]
        public void L2Norm()
        {
            Matrix matrix = GetMatrix(square);
            Assert.AreEqual(10.391347375312632, matrix.L2Norm(), Constants.ACCEPTABLE_ERROR);

            matrix = GetMatrix(wide);
            Assert.AreEqual(4.7540849434107635, matrix.L2Norm(), Constants.ACCEPTABLE_ERROR);

            matrix = GetMatrix(tall);
            Assert.AreEqual(7.182727033856683, matrix.L2Norm(), Constants.ACCEPTABLE_ERROR);
        }

        [Test]
        public void Transpose()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = matrix.Transpose();

            Assert.AreEqual(matrix.Rows, result.Columns);
            Assert.AreEqual(matrix.Columns, result.Rows);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], result[j, i]);
                }
            }

            matrix = GetMatrix(wide);
            result = matrix.Transpose();
            Assert.AreEqual(matrix.Rows, result.Columns);
            Assert.AreEqual(matrix.Columns, result.Rows);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], result[j, i]);
                }
            }

            matrix = GetMatrix(tall);
            result = matrix.Transpose();
            Assert.AreEqual(matrix.Rows, result.Columns);
            Assert.AreEqual(matrix.Columns, result.Rows);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], result[j, i]);
                }
            }
        }

        [Test]
        public void TransposeResult()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = GetMatrix(matrix.Columns, matrix.Rows);
            matrix.Transpose(result);
            Assert.AreEqual(matrix.Rows, result.Columns);
            Assert.AreEqual(matrix.Columns, result.Rows);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], result[j, i]);
                }
            }

            matrix = GetMatrix(wide);
            result = GetMatrix(matrix.Columns, matrix.Rows);
            matrix.Transpose(result);
            Assert.AreEqual(matrix.Rows, result.Columns);
            Assert.AreEqual(matrix.Columns, result.Rows);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], result[j, i]);
                }
            }

            matrix = GetMatrix(tall);
            result = GetMatrix(matrix.Columns, matrix.Rows);
            matrix.Transpose(result);
            Assert.AreEqual(matrix.Rows, result.Columns);
            Assert.AreEqual(matrix.Columns, result.Rows);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], result[j, i]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void TransposeResultNull()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = null;
            matrix.Transpose(result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void TransposeResultNotConformable()
        {
            Matrix matrix = GetMatrix(wide);
            Matrix result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Transpose(result);
        }

        [Test]
        public void Inverse()
        {
            Matrix matrix = GetMatrix(square);
            Matrix inverse = matrix.Inverse();

            Assert.AreEqual(matrix.Rows, inverse.Rows);
            Assert.AreEqual(matrix.Columns, inverse.Columns);
            Matrix identity = GetMatrix(matrix.Rows);
            matrix.Multiply(inverse, identity);

            for (int i = 0; i < identity.Rows; i++)
            {
                for (int j = 0; j < identity.Columns; j++)
                {
                    if (i == j)
                    {
                        Assert.AreEqual(1, identity[i, j], Constants.ACCEPTABLE_ERROR);
                    }
                    else
                    {
                        Assert.AreEqual(0, identity[i, j], Constants.ACCEPTABLE_ERROR);
                    }
                }
            }
        }

        [Test]
        [ExpectedException(typeof(SingularMatrixException))]
        public void InverseSingular()
        {
            Matrix singularMatrix = GetMatrix(singular);
            Matrix inverse = singularMatrix.Inverse();
        }

        [Test]
        [ExpectedException(typeof(NotSquareMatrixException))]
        public void InverseNotSquareMatrix()
        {
            Matrix matrix = GetMatrix(wide);
            Matrix inverse = matrix.Inverse();
        }

        [Test]
        public void InverseResult()
        {
            Matrix matrix = GetMatrix(square);
            Matrix inverse = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Inverse(inverse);
            Matrix identity = GetMatrix(matrix.Rows);
            matrix.Multiply(inverse, identity);
            for (int i = 0; i < identity.Rows; i++)
            {
                for (int j = 0; j < identity.Columns; j++)
                {
                    if (i == j)
                    {
                        Assert.AreEqual(1, identity[i, j], Constants.ACCEPTABLE_ERROR);
                    }
                    else
                    {
                        Assert.AreEqual(0, identity[i, j], Constants.ACCEPTABLE_ERROR);
                    }
                }
            }
        }

        [Test]
        [ExpectedException(typeof(SingularMatrixException))]
        public void InverseSingularResult()
        {
            Matrix singularMatrix = GetMatrix(singular);
            Matrix inverse = GetMatrix(singularMatrix.Rows);
            singularMatrix.Inverse(inverse);
        }


        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void InverseResultNull()
        {
            Matrix matrix = GetMatrix(square);
            Matrix inverse = null;
            matrix.Inverse(inverse);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void InverseResultNotConformable()
        {
            Matrix matrix = GetMatrix(square);
            Matrix inverse = GetMatrix(matrix.Rows + 1, matrix.Columns + 1);
            matrix.Inverse(inverse);
        }

        [Test]
        [ExpectedException(typeof(NotSquareMatrixException))]
        public void InverseResultNotSquareMatrix()
        {
            Matrix matrix = GetMatrix(wide);
            Matrix inverse = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Inverse(inverse);
        }

        [Test]
        public void LeftMultiplyVector()
        {
            Matrix matrix = GetMatrix(square);
            Vector vector = GetVector(new double[] { 1.1, 2.2, 3.3 });
            Vector result = matrix.LeftMultiply(vector);
            Assert.AreEqual(matrix.Columns, result.Count);
            Assert.AreEqual(-15.73, result[0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(18.15, result[1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(22.99, result[2], Constants.ACCEPTABLE_ERROR);

            matrix = GetMatrix(wide);
            vector = GetVector(new double[] { 1.1, 2.2 });
            result = matrix.LeftMultiply(vector);
            Assert.AreEqual(matrix.Columns, result.Count);
            Assert.AreEqual(-1.21, result[0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(0, result[1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(1.21, result[2], Constants.ACCEPTABLE_ERROR);

            matrix = GetMatrix(tall);
            vector = GetVector(new double[] { 1.1, 2.2, 3.3 });
            result = matrix.LeftMultiply(vector);
            Assert.AreEqual(matrix.Columns, result.Count);
            Assert.AreEqual(-15.73, result[0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(18.15, result[1], Constants.ACCEPTABLE_ERROR);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void LeftMultiplyVectorNull()
        {
            Matrix matrix = GetMatrix(square);
            Vector leftSide = null;
            matrix.LeftMultiply(leftSide);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void LeftMultiplyVectorNotConformable()
        {
            Matrix matrix = GetMatrix(square);
            Vector leftSide = GetVector(matrix.Rows + 1);
            matrix.LeftMultiply(leftSide);
        }

        [Test]
        public void LeftMultiplyVectorResult()
        {
            Matrix matrix = GetMatrix(square);
            Vector vector = GetVector(new double[] { 1.1, 2.2, 3.3 });
            Vector result = GetVector(matrix.Columns);
            matrix.LeftMultiply(vector, result);
            Assert.AreEqual(-15.73, result[0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(18.15, result[1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(22.99, result[2], Constants.ACCEPTABLE_ERROR);

            matrix = GetMatrix(wide);
            vector = GetVector(new double[] { 1.1, 2.2 });
            result = GetVector(matrix.Columns);
            matrix.LeftMultiply(vector, result);
            Assert.AreEqual(matrix.Columns, result.Count);
            Assert.AreEqual(-1.21, result[0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(0, result[1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(1.21, result[2], Constants.ACCEPTABLE_ERROR);

            matrix = GetMatrix(tall);
            vector = GetVector(new double[] { 1.1, 2.2, 3.3 });
            result = GetVector(matrix.Columns);
            matrix.LeftMultiply(vector, result);
            Assert.AreEqual(matrix.Columns, result.Count);
            Assert.AreEqual(-15.73, result[0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(18.15, result[1], Constants.ACCEPTABLE_ERROR);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void LeftMultiplyVectorResultNull1()
        {
            Matrix matrix = GetMatrix(square);
            Vector leftSide = null;
            Vector result = GetVector(matrix.Columns);
            matrix.LeftMultiply(leftSide, result);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void LeftMultiplyVectorResultNull2()
        {
            Matrix matrix = GetMatrix(square);
            Vector leftSide = GetVector(matrix.Rows);
            Vector result = null;
            matrix.LeftMultiply(leftSide, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void LeftMultiplyVectorResultNotConformable1()
        {
            Matrix matrix = GetMatrix(square);
            Vector leftSide = GetVector(matrix.Rows + 1); ;
            Vector result = GetVector(matrix.Columns);
            matrix.LeftMultiply(leftSide, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void LeftMultiplyVectorResultNotConformable2()
        {
            Matrix matrix = GetMatrix(square);
            Vector leftSide = GetVector(matrix.Rows); ;
            Vector result = GetVector(matrix.Columns + 1);
            matrix.LeftMultiply(leftSide, result);
        }

        [Test]
        public void LowerTriangle()
        {
            Matrix matrix = GetMatrix(square);
            Matrix lower = matrix.LowerTriangle();
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i >= j)
                    {
                        Assert.AreEqual(matrix[i, j], lower[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, lower[i, j]);
                    }
                }
            }

            matrix = GetMatrix(wide);
            lower = matrix.LowerTriangle();
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i >= j)
                    {
                        Assert.AreEqual(matrix[i, j], lower[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, lower[i, j]);
                    }
                }
            }

            matrix = GetMatrix(tall);
            lower = matrix.LowerTriangle();
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i >= j)
                    {
                        Assert.AreEqual(matrix[i, j], lower[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, lower[i, j]);
                    }
                }
            }
        }

        [Test]
        public void LowerTriangleResult()
        {
            Matrix matrix = GetMatrix(square);
            Matrix lower = GetMatrix(square);
            matrix.LowerTriangle(lower);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i >= j)
                    {
                        Assert.AreEqual(matrix[i, j], lower[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, lower[i, j]);
                    }
                }
            }

            matrix = GetMatrix(wide);
            lower = GetMatrix(wide);
            matrix.LowerTriangle(lower);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i >= j)
                    {
                        Assert.AreEqual(matrix[i, j], lower[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, lower[i, j]);
                    }
                }
            }

            matrix = GetMatrix(tall);
            lower = GetMatrix(tall);
            matrix.LowerTriangle(lower);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i >= j)
                    {
                        Assert.AreEqual(matrix[i, j], lower[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, lower[i, j]);
                    }
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void LowerTriangleResultNull()
        {
            Matrix matrix = GetMatrix(square);
            Matrix lower = null;
            matrix.LowerTriangle(lower);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void LowerTriangleResultNotConformableException1()
        {
            Matrix matrix = GetMatrix(square);
            Matrix lower = GetMatrix(matrix.Rows + 1, matrix.Columns);
            matrix.LowerTriangle(lower);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void LowerTriangleResultNotConformableException2()
        {
            Matrix matrix = GetMatrix(square);
            Matrix lower = GetMatrix(matrix.Rows, matrix.Columns + 1);
            matrix.LowerTriangle(lower);
        }

        [Test]
        public void StrictlyLowerTriangle()
        {
            Matrix matrix = GetMatrix(square);
            Matrix lower = matrix.StrictlyLowerTriangle();
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i > j)
                    {
                        Assert.AreEqual(matrix[i, j], lower[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, lower[i, j]);
                    }
                }
            }

            matrix = GetMatrix(wide);
            lower = matrix.StrictlyLowerTriangle();
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i > j)
                    {
                        Assert.AreEqual(matrix[i, j], lower[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, lower[i, j]);
                    }
                }
            }

            matrix = GetMatrix(tall);
            lower = matrix.StrictlyLowerTriangle();
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i > j)
                    {
                        Assert.AreEqual(matrix[i, j], lower[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, lower[i, j]);
                    }
                }
            }
        }

        [Test]
        public void StrictlyLowerTriangleResult()
        {
            Matrix matrix = GetMatrix(square);
            Matrix lower = GetMatrix(square);
            matrix.StrictlyLowerTriangle(lower);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i > j)
                    {
                        Assert.AreEqual(matrix[i, j], lower[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, lower[i, j]);
                    }
                }
            }

            matrix = GetMatrix(wide);
            lower = GetMatrix(wide);
            matrix.StrictlyLowerTriangle(lower);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i > j)
                    {
                        Assert.AreEqual(matrix[i, j], lower[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, lower[i, j]);
                    }
                }
            }

            matrix = GetMatrix(tall);
            lower = GetMatrix(tall);
            matrix.StrictlyLowerTriangle(lower);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i > j)
                    {
                        Assert.AreEqual(matrix[i, j], lower[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, lower[i, j]);
                    }
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void StrictlyLowerTriangleResultNull()
        {
            Matrix matrix = GetMatrix(square);
            Matrix lower = null;
            matrix.StrictlyLowerTriangle(lower);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void StrictlyLowerTriangleResultNotConformableException1()
        {
            Matrix matrix = GetMatrix(square);
            Matrix lower = GetMatrix(matrix.Rows + 1, matrix.Columns);
            matrix.StrictlyLowerTriangle(lower);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void StrictlyLowerTriangleResultNotConformableException2()
        {
            Matrix matrix = GetMatrix(square);
            Matrix lower = GetMatrix(matrix.Rows, matrix.Columns + 1);
            matrix.StrictlyLowerTriangle(lower);
        }

        [Test]
        public void UpperTriangle()
        {
            Matrix matrix = GetMatrix(square);
            Matrix upper = matrix.UpperTriangle();
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i <= j)
                    {
                        Assert.AreEqual(matrix[i, j], upper[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, upper[i, j]);
                    }
                }
            }

            matrix = GetMatrix(wide);
            upper = matrix.UpperTriangle();
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i <= j)
                    {
                        Assert.AreEqual(matrix[i, j], upper[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, upper[i, j]);
                    }
                }
            }

            matrix = GetMatrix(tall);
            upper = matrix.UpperTriangle();
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i <= j)
                    {
                        Assert.AreEqual(matrix[i, j], upper[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, upper[i, j]);
                    }
                }
            }
        }

        [Test]
        public void UpperTriangleResult()
        {
            Matrix matrix = GetMatrix(square);
            Matrix upper = GetMatrix(square);
            matrix.UpperTriangle(upper);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i <= j)
                    {
                        Assert.AreEqual(matrix[i, j], upper[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, upper[i, j]);
                    }
                }
            }

            matrix = GetMatrix(wide);
            upper = GetMatrix(wide);
            matrix.UpperTriangle(upper);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i <= j)
                    {
                        Assert.AreEqual(matrix[i, j], upper[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, upper[i, j]);
                    }
                }
            }

            matrix = GetMatrix(tall);
            upper = GetMatrix(tall);
            matrix.UpperTriangle(upper);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i <= j)
                    {
                        Assert.AreEqual(matrix[i, j], upper[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, upper[i, j]);
                    }
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void UpperTriangleResultNull()
        {
            Matrix matrix = GetMatrix(square);
            Matrix upper = null;
            matrix.UpperTriangle(upper);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void UpperTriangleResultNotConformableException1()
        {
            Matrix matrix = GetMatrix(square);
            Matrix upper = GetMatrix(matrix.Rows + 1, matrix.Columns);
            matrix.UpperTriangle(upper);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void UpperTriangleResultNotConformableException2()
        {
            Matrix matrix = GetMatrix(square);
            Matrix upper = GetMatrix(matrix.Rows, matrix.Columns + 1);
            matrix.UpperTriangle(upper);
        }

        [Test]
        public void StrictlyUpperTriangle()
        {
            Matrix matrix = GetMatrix(square);
            Matrix upper = matrix.StrictlyUpperTriangle();
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i < j)
                    {
                        Assert.AreEqual(matrix[i, j], upper[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, upper[i, j]);
                    }
                }
            }

            matrix = GetMatrix(wide);
            upper = matrix.StrictlyUpperTriangle();
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i < j)
                    {
                        Assert.AreEqual(matrix[i, j], upper[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, upper[i, j]);
                    }
                }
            }

            matrix = GetMatrix(tall);
            upper = matrix.StrictlyUpperTriangle();
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i < j)
                    {
                        Assert.AreEqual(matrix[i, j], upper[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, upper[i, j]);
                    }
                }
            }
        }

        [Test]
        public void StrictlyUpperTriangleResult()
        {
            Matrix matrix = GetMatrix(square);
            Matrix upper = GetMatrix(square);
            matrix.StrictlyUpperTriangle(upper);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i < j)
                    {
                        Assert.AreEqual(matrix[i, j], upper[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, upper[i, j]);
                    }
                }
            }

            matrix = GetMatrix(wide);
            upper = GetMatrix(wide);
            matrix.StrictlyUpperTriangle(upper);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i < j)
                    {
                        Assert.AreEqual(matrix[i, j], upper[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, upper[i, j]);
                    }
                }
            }

            matrix = GetMatrix(tall);
            upper = GetMatrix(tall);
            matrix.StrictlyUpperTriangle(upper);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    if (i < j)
                    {
                        Assert.AreEqual(matrix[i, j], upper[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(0, upper[i, j]);
                    }
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void StrictlyUpperTriangleResultNull()
        {
            Matrix matrix = GetMatrix(square);
            Matrix upper = null;
            matrix.StrictlyUpperTriangle(upper);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void StrictlyUpperTriangleResultNotConformableException1()
        {
            Matrix matrix = GetMatrix(square);
            Matrix upper = GetMatrix(matrix.Rows + 1, matrix.Columns);
            matrix.StrictlyUpperTriangle(upper);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void StrictlyUpperTriangleResultNotConformableException2()
        {
            Matrix matrix = GetMatrix(square);
            Matrix upper = GetMatrix(matrix.Rows, matrix.Columns + 1);
            matrix.StrictlyUpperTriangle(upper);
        }

        [Test]
        public void MultiplyScalar()
        {
            Matrix matrix = GetMatrix(square);
            matrix.Multiply(2.3);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] * 2.3, matrix[i, j], Constants.ACCEPTABLE_ERROR);
                }
            }

            matrix = GetMatrix(wide);
            matrix.Multiply(2.3);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(wide[i, j] * 2.3, matrix[i, j], Constants.ACCEPTABLE_ERROR);
                }
            }

            matrix = GetMatrix(tall);
            matrix.Multiply(2.3);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(tall[i, j] * 2.3, matrix[i, j], Constants.ACCEPTABLE_ERROR);
                }
            }
        }

        [Test]
        public void MultiplyScalarResult()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Multiply(2.3, result);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] * 2.3, result[i, j], Constants.ACCEPTABLE_ERROR);
                }
            }

            matrix = GetMatrix(wide);
            result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Multiply(2.3, result);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(wide[i, j] * 2.3, result[i, j], Constants.ACCEPTABLE_ERROR);
                }
            }

            matrix = GetMatrix(tall);
            result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Multiply(2.3, result);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(tall[i, j] * 2.3, result[i, j], Constants.ACCEPTABLE_ERROR);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void MultiplyScalarResultNull()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = null;
            matrix.Multiply(2.3, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void MultiplyScalarResultNotConformable1()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = GetMatrix(matrix.Rows + 1, matrix.Columns);
            matrix.Multiply(2.3, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void MultiplyScalarResultNotConformable2()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = GetMatrix(matrix.Rows, matrix.Columns + 1);
            matrix.Multiply(2.3, result);
        }

        [Test]
        public void MultiplyMatrix()
        {
            Matrix matrix1 = GetMatrix(square);
            Matrix matrix2 = matrix1.Clone();
            Matrix result = matrix1.Multiply(matrix2);

            Assert.AreEqual(3, result.Rows);
            Assert.AreEqual(3, result.Columns);
            Assert.AreEqual(15.73, result[0, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(-18.15, result[0, 1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(-22.99, result[0, 2], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(-9.68, result[1, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(13.31, result[1, 1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(16.94, result[1, 2], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(-24.2, result[2, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(52.03, result[2, 1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(70.17999999999999, result[2, 2], Constants.ACCEPTABLE_ERROR);

            matrix1 = GetMatrix(wide);
            matrix2 = GetMatrix(tall);
            result = matrix1.Multiply(matrix2);
            Assert.AreEqual(2, result.Rows);
            Assert.AreEqual(2, result.Columns);
            Assert.AreEqual(15.73, result[0, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(-18.15, result[0, 1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(-9.68, result[1, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(13.31, result[1, 1], Constants.ACCEPTABLE_ERROR);

            matrix1 = GetMatrix(tall);
            matrix2 = GetMatrix(wide);
            result = matrix1.Multiply(matrix2);
            Assert.AreEqual(3, result.Rows);
            Assert.AreEqual(3, result.Columns);
            Assert.AreEqual(1.21, result[0, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(0, result[0, 1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(-1.21, result[0, 2], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(0, result[1, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(1.21, result[1, 1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(2.42, result[1, 2], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(4.84, result[2, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(15.73, result[2, 1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(26.62, result[2, 2], Constants.ACCEPTABLE_ERROR);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void MultiplyMatrixNull()
        {
            Matrix matrix1 = GetMatrix(square);
            Matrix matrix2 = null;
            matrix1.Multiply(matrix2);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void MultiplyMatrixNotConformable()
        {
            Matrix matrix1 = GetMatrix(square);
            Matrix matrix2 = GetMatrix(matrix1.Rows + 1, matrix1.Columns);
            matrix1.Multiply(matrix2);
        }

        [Test]
        public void MultiplyMatrixResult()
        {
            Matrix matrix1 = GetMatrix(square);
            Matrix matrix2 = GetMatrix(square);
            Matrix result = GetMatrix(matrix1.Rows, matrix2.Columns);
            matrix1.Multiply(matrix2, result);

            Assert.AreEqual(3, result.Rows);
            Assert.AreEqual(3, result.Columns);
            Assert.AreEqual(15.73, result[0, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(-18.15, result[0, 1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(-22.99, result[0, 2], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(-9.68, result[1, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(13.31, result[1, 1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(16.94, result[1, 2], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(-24.2, result[2, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(52.03, result[2, 1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(70.17999999999999, result[2, 2], Constants.ACCEPTABLE_ERROR);

            matrix1 = GetMatrix(wide);
            matrix2 = GetMatrix(tall);
            result = GetMatrix(matrix1.Rows, matrix2.Columns);
            matrix1.Multiply(matrix2, result);

            Assert.AreEqual(2, result.Rows);
            Assert.AreEqual(2, result.Columns);
            Assert.AreEqual(15.73, result[0, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(-18.15, result[0, 1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(-9.68, result[1, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(13.31, result[1, 1], Constants.ACCEPTABLE_ERROR);

            matrix1 = GetMatrix(tall);
            matrix2 = GetMatrix(wide);
            result = GetMatrix(matrix1.Rows, matrix2.Columns);
            matrix1.Multiply(matrix2, result);
            Assert.AreEqual(3, result.Rows);
            Assert.AreEqual(3, result.Columns);
            Assert.AreEqual(1.21, result[0, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(0, result[0, 1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(-1.21, result[0, 2], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(0, result[1, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(1.21, result[1, 1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(2.42, result[1, 2], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(4.84, result[2, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(15.73, result[2, 1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(26.62, result[2, 2], Constants.ACCEPTABLE_ERROR);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void MultiplyMatrixResultNull1()
        {
            Matrix matrix1 = GetMatrix(square);
            Matrix matrix2 = null;
            Matrix result = GetMatrix(matrix1.Rows, matrix1.Columns);
            matrix1.Multiply(matrix2, result);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void MultiplyMatrixResultNull2()
        {
            Matrix matrix1 = GetMatrix(square);
            Matrix matrix2 = GetMatrix(square);
            Matrix result = null;
            matrix1.Multiply(matrix2, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void MultiplyMatrixResultNotConformable1()
        {
            Matrix matrix1 = GetMatrix(square);
            Matrix matrix2 = GetMatrix(matrix1.Rows + 1, matrix1.Columns);
            Matrix result = GetMatrix(matrix1.Rows, matrix2.Columns);
            matrix1.Multiply(matrix2, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void MultiplyMatrixResultNotConformable2()
        {
            Matrix matrix1 = GetMatrix(square);
            Matrix matrix2 = GetMatrix(matrix1.Rows, matrix1.Columns);
            Matrix result = GetMatrix(matrix1.Rows + 1, matrix2.Columns);
            matrix1.Multiply(matrix2, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void MultiplyMatrixResultNotConformable3()
        {
            Matrix matrix1 = GetMatrix(square);
            Matrix matrix2 = GetMatrix(matrix1.Rows, matrix1.Columns);
            Matrix result = GetMatrix(matrix1.Rows, matrix2.Columns + 1);
            matrix1.Multiply(matrix2, result);
        }

        [Test]
        public void MultiplyVector()
        {
            Matrix matrix = GetMatrix(square);
            Vector vector = GetVector(new double[] { 1.1, 2.2, 3.3 });
            Vector result = matrix.Multiply(vector);
            Assert.AreEqual(matrix.Rows, result.Count);
            Assert.AreEqual(-16.94, result[0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(9.68, result[1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(29.04, result[2], Constants.ACCEPTABLE_ERROR);

            matrix = GetMatrix(wide);
            vector = GetVector(new double[] { 1.1, 2.2, 3.3 });
            result = matrix.Multiply(vector);
            Assert.AreEqual(matrix.Rows, result.Count);
            Assert.AreEqual(-16.94, result[0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(9.68, result[1], Constants.ACCEPTABLE_ERROR);

            matrix = GetMatrix(tall);
            vector = GetVector(new double[] { 1.1, 2.2 });
            result = matrix.Multiply(vector);
            Assert.AreEqual(matrix.Rows, result.Count);
            Assert.AreEqual(-6.05, result[0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(2.42, result[1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(7.26, result[2], Constants.ACCEPTABLE_ERROR);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void MultiplyVectorNull()
        {
            Matrix matrix = GetMatrix(square);
            Vector rightSide = null;
            matrix.Multiply(rightSide);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void MultiplyVectorNotConformable()
        {
            Matrix matrix = GetMatrix(square);
            Vector rightSide = GetVector(matrix.Columns + 1);
            matrix.Multiply(rightSide);
        }

        [Test]
        public void MultiplyVectorResult()
        {
            Matrix matrix = GetMatrix(square);
            Vector vector = GetVector(new double[] { 1.1, 2.2, 3.3 });
            Vector result = GetVector(matrix.Rows);
            matrix.Multiply(vector, result);
            Assert.AreEqual(matrix.Rows, result.Count);
            Assert.AreEqual(-16.94, result[0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(9.68, result[1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(29.04, result[2], Constants.ACCEPTABLE_ERROR);

            matrix = GetMatrix(wide);
            vector = GetVector(new double[] { 1.1, 2.2, 3.3 });
            result = GetVector(matrix.Rows);
            matrix.Multiply(vector, result);
            Assert.AreEqual(matrix.Rows, result.Count);
            Assert.AreEqual(-16.94, result[0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(9.68, result[1], Constants.ACCEPTABLE_ERROR);

            matrix = GetMatrix(tall);
            vector = GetVector(new double[] { 1.1, 2.2 });
            result = GetVector(matrix.Rows);
            matrix.Multiply(vector, result);
            Assert.AreEqual(matrix.Rows, result.Count);
            Assert.AreEqual(-6.05, result[0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(2.42, result[1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(7.26, result[2], Constants.ACCEPTABLE_ERROR);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void MultiplyVectorResultNull1()
        {
            Matrix matrix = GetMatrix(square);
            Vector rightSide = null;
            Vector result = GetVector(matrix.Rows);
            matrix.Multiply(rightSide, result);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void MultiplyVectorResultNull2()
        {
            Matrix matrix = GetMatrix(square);
            Vector rightSide = GetVector(matrix.Columns);
            Vector result = null;
            matrix.Multiply(rightSide, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void MultiplyVectorResultNotConformable1()
        {
            Matrix matrix = GetMatrix(square);
            Vector rightSide = GetVector(matrix.Columns + 1); ;
            Vector result = GetVector(matrix.Rows);
            matrix.Multiply(rightSide, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void MultiplyVectorResultNotConformable2()
        {
            Matrix matrix = GetMatrix(square);
            Vector rightSide = GetVector(matrix.Columns); ;
            Vector result = GetVector(matrix.Rows + 1);
            matrix.Multiply(rightSide, result);
        }

        [Test]
        public void Negate()
        {
            Matrix matrix = GetMatrix(square);
            matrix.Negate();
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(-square[i, j], matrix[i, j]);
                }
            }

            matrix = GetMatrix(wide);
            matrix.Negate();
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(-wide[i, j], matrix[i, j]);
                }
            }

            matrix = GetMatrix(tall);
            matrix.Negate();
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(-tall[i, j], matrix[i, j]);
                }
            }
        }

        [Test]
        public void NegateResult()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Negate(result);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(-square[i, j], result[i, j]);
                }
            }

            matrix = GetMatrix(wide);
            result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Negate(result);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(-wide[i, j], result[i, j]);
                }
            }

            matrix = GetMatrix(tall);
            result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Negate(result);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(-tall[i, j], result[i, j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void NegateResultNull()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = null;
            matrix.Negate(result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void NegateResultNotConformable1()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = GetMatrix(matrix.Rows + 1, matrix.Columns);
            matrix.Negate(result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void NegateResultNotConformable2()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = GetMatrix(matrix.Rows, matrix.Columns + 1);
            matrix.Negate(result);
        }

        [Test]
        public void Row()
        {
            Matrix matrix = GetMatrix(square);
            for (int i = 0; i < matrix.Rows; i++)
            {
                Vector row = matrix.Row(i);

                Assert.AreEqual(matrix.Columns, row.Count);
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], row[j]);
                }
            }

            matrix = GetMatrix(wide);
            for (int i = 0; i < matrix.Rows; i++)
            {
                Vector row = matrix.Row(i);
                Assert.AreEqual(matrix.Columns, row.Count);
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], row[j]);
                }
            }

            matrix = GetMatrix(tall);
            for (int i = 0; i < matrix.Rows; i++)
            {
                Vector row = matrix.Row(i);
                Assert.AreEqual(matrix.Columns, row.Count);
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], row[j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void RowArgumentOutOfRange1()
        {
            Matrix matrix = GetMatrix(square);
            Vector row = matrix.Row(-1);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void RowArgumentOutOfRange2()
        {
            Matrix matrix = GetMatrix(square);
            Vector row = matrix.Row(matrix.Columns);
        }

        [Test]
        public void RowResult()
        {
            Matrix matrix = GetMatrix(square);
            for (int i = 0; i < matrix.Rows; i++)
            {
                Vector row = GetVector(matrix.Columns);
                matrix.Row(i, row);
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], row[j]);
                }
            }

            matrix = GetMatrix(wide);
            for (int i = 0; i < matrix.Rows; i++)
            {
                Vector row = GetVector(matrix.Columns);
                matrix.Row(i, row);
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], row[j]);
                }
            }

            matrix = GetMatrix(tall);
            for (int i = 0; i < matrix.Rows; i++)
            {
                Vector row = GetVector(matrix.Columns);
                matrix.Row(i, row);
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], row[j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void RowResultNull()
        {
            Matrix matrix = GetMatrix(square);
            Vector row = null;
            matrix.Row(0, row);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void RowResultArgumentOutOfRange1()
        {
            Matrix matrix = GetMatrix(square);
            Vector row = GetVector(matrix.Columns);
            matrix.Row(-1, row);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void RowResultArgumentOutOfRange2()
        {
            Matrix matrix = GetMatrix(square);
            Vector row = GetVector(matrix.Columns);
            matrix.Row(matrix.Columns, row);
        }
        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void RowResultNotConformable()
        {
            Matrix matrix = GetMatrix(square);
            Vector row = GetVector(matrix.Columns + 1);
            matrix.Row(0, row);
        }

        [Test]
        public void RowRange()
        {
            Matrix matrix = GetMatrix(square);
            Range range = new Range(0, matrix.Columns - 1, 2);
            for (int i = 0; i < matrix.Rows; i++)
            {
                Vector row = matrix.Row(i, range);
                Assert.AreEqual((range.End - range.Start) / range.Stride + 1, row.Count);
                for (int j = range.Start, k = 0; j <= range.End; j += range.Stride, k++)
                {
                    Assert.AreEqual(matrix[i, j], row[k]);
                }
            }

            matrix = GetMatrix(wide);
            range = new Range(0, matrix.Columns - 1, 2);
            for (int i = 0; i < matrix.Rows; i++)
            {
                Vector row = matrix.Row(i, range);
                Assert.AreEqual((range.End - range.Start) / range.Stride + 1, row.Count);
                for (int j = range.Start, k = 0; j <= range.End; j += range.Stride, k++)
                {
                    Assert.AreEqual(matrix[i, j], row[k]);
                }
            }

            matrix = GetMatrix(tall);
            range = new Range(0, matrix.Columns - 1, 2);
            for (int i = 0; i < matrix.Rows; i++)
            {
                Vector row = matrix.Row(i, range);
                Assert.AreEqual((range.End - range.Start) / range.Stride + 1, row.Count);
                for (int j = range.Start, k = 0; j <= range.End; j += range.Stride, k++)
                {
                    Assert.AreEqual(matrix[i, j], row[k]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void RowIndexArgumentOutOfRange1()
        {
            Matrix matrix = GetMatrix(square);
            Range range = new Range(0, matrix.Columns - 1);
            Vector row = matrix.Row(-1, range);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void RowIndexArgumentOutOfRange2()
        {
            Matrix matrix = GetMatrix(square);
            Range range = new Range(0, matrix.Columns - 1);
            Vector row = matrix.Row(matrix.Columns, range);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void RowRangeArgumentOutOfRange1()
        {
            Matrix matrix = GetMatrix(square);
            Range range = new Range(0, matrix.Columns);
            Vector row = matrix.Row(0, range);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void RowRangeArgumentOutOfRange2()
        {
            Matrix matrix = GetMatrix(square);
            Range range = new Range(matrix.Columns, matrix.Columns + 1);
            Vector row = matrix.Row(0, range);
        }
        [Test]
        public void RowEnumerator()
        {
            Matrix matrix = GetMatrix(square);
            foreach(KeyValuePair<int, Vector> row in matrix.RowEnumerator()){
                foreach (KeyValuePair<int, double> value in row.Value)
                {
                    Assert.AreEqual(matrix[row.Key, value.Key], value.Value);
                }
            }

            matrix = GetMatrix(wide);
            foreach (KeyValuePair<int, Vector> row in matrix.RowEnumerator())
            {
                foreach (KeyValuePair<int, double> value in row.Value)
                {
                    Assert.AreEqual(matrix[row.Key, value.Key], value.Value);
                }
            }

            GetMatrix(tall);
            foreach (KeyValuePair<int, Vector> row in matrix.RowEnumerator())
            {
                foreach (KeyValuePair<int, double> value in row.Value)
                {
                    Assert.AreEqual(matrix[row.Key, value.Key], value.Value);
                }
            }
        }

        [Test]
        public void RowEnumeratorRange()
        {
            Matrix matrix = GetMatrix(square);
            Range range = new Range(0, matrix.Rows - 1, 2);
            foreach (KeyValuePair<int, Vector> row in matrix.RowEnumerator(range))
            {
                foreach (KeyValuePair<int, double> value in row.Value)
                {
                    Assert.AreEqual(matrix[row.Key, value.Key], value.Value);
                }
            }

            matrix = GetMatrix(square);
            range = new Range(0, matrix.Rows - 1, 2);
            foreach (KeyValuePair<int, Vector> row in matrix.RowEnumerator(range))
            {
                foreach (KeyValuePair<int, double> value in row.Value)
                {
                    Assert.AreEqual(matrix[row.Key, value.Key], value.Value);
                }
            }

            matrix = GetMatrix(square);
            range = new Range(0, matrix.Rows - 1, 2);
            foreach (KeyValuePair<int, Vector> row in matrix.RowEnumerator(range))
            {
                foreach (KeyValuePair<int, double> value in row.Value)
                {
                    Assert.AreEqual(matrix[row.Key, value.Key], value.Value);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void RowEnumeratorRangeArgumentOutOfRange1()
        {
            Matrix matrix = GetMatrix(square);
            Range range = new Range(matrix.Rows, matrix.Rows + 1);
            foreach (KeyValuePair<int, Vector> row in matrix.RowEnumerator(range)){}
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void RowEnumeratorRangeArgumentOutOfRange2()
        {
            Matrix matrix = GetMatrix(square);
            Range range = new Range(0, matrix.Rows + 1);
            foreach (KeyValuePair<int, Vector> row in matrix.RowEnumerator(range)) { }
        }
        
        [Test]
        public void SetColumnVector()
        {
            Matrix matrix = GetMatrix(square);
            double[] array = new double[] { 1, 2, 3 };
            Vector vector = GetVector(array);
            for (int i = 0; i < matrix.Columns; i++)
            {
                matrix.SetColumn(i, vector);
                for (int j = 0; j < matrix.Rows; j++)
                {
                    Assert.AreEqual(array[j], matrix[j, i]);
                }
            }

            matrix = GetMatrix(tall);
            array = new double[] { 1, 2, 3 };
            vector = GetVector(array);
            for (int i = 0; i < matrix.Columns; i++)
            {
                matrix.SetColumn(i, vector);
                for (int j = 0; j < matrix.Rows; j++)
                {
                    Assert.AreEqual(array[j], matrix[j, i]);
                }
            }

            matrix = GetMatrix(wide);
            array = new double[] { 1, 2 };
            vector = GetVector(array);
            for (int i = 0; i < matrix.Columns; i++)
            {
                matrix.SetColumn(i, vector);
                for (int j = 0; j < array.Length; j++)
                {
                    Assert.AreEqual(array[j], matrix[j, i]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SetColumnVectorNull()
        {
            Matrix matrix = GetMatrix(square);
            Vector vector = null;
            matrix.SetColumn(0, vector);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SetColumnVectorArgumentOutOfRange1()
        {
            Matrix matrix = GetMatrix(square);
            double[] array = new double[] { 1, 2, 3 };
            Vector vector = GetVector(array);
            matrix.SetColumn(-1, vector);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SetColumnVectorArgumentOutOfRange2()
        {
            Matrix matrix = GetMatrix(square);
            double[] array = new double[] { 1, 2, 3 };
            Vector vector = GetVector(array);
            matrix.SetColumn(matrix.Columns + 1, vector);
        }

        [Test]
        public void SetColumnArray()
        {
            Matrix matrix = GetMatrix(square);
            double[] array = new double[] { 1, 2, 3 };
            for (int i = 0; i < matrix.Columns; i++)
            {
                matrix.SetColumn(i, array);
                for (int j = 0; j < matrix.Rows; j++)
                {
                    Assert.AreEqual(array[j], matrix[j, i]);
                }
            }

            matrix = GetMatrix(tall);
            array = new double[] { 1, 2, 3 };
            for (int i = 0; i < matrix.Columns; i++)
            {
                matrix.SetColumn(i, array);
                for (int j = 0; j < matrix.Rows; j++)
                {
                    Assert.AreEqual(array[j], matrix[j, i]);
                }
            }

            matrix = GetMatrix(wide);
            array = new double[] { 1, 2 };
            for (int i = 0; i < matrix.Columns; i++)
            {
                matrix.SetColumn(i, array);
                for (int j = 0; j < array.Length; j++)
                {
                    Assert.AreEqual(array[j], matrix[j, i]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SetColumnArrayNull()
        {
            Matrix matrix = GetMatrix(square);
            double[] array = null;
            matrix.SetColumn(0, array);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SetColumnArrayArgumentOutOfRange1()
        {
            Matrix matrix = GetMatrix(square);
            double[] array = new double[] { 1, 2, 3 };
            matrix.SetColumn(-1, array);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SetColumnArrayArgumentOutOfRange2()
        {
            Matrix matrix = GetMatrix(square);
            double[] array = new double[] { 1, 2, 3 };
            matrix.SetColumn(matrix.Columns + 1, array);
        }

        [Test]
        public void SetRowVector()
        {
            Matrix matrix = GetMatrix(square);
            double[] array = new double[] { 1, 2, 3 };
            Vector vector = GetVector(array);
            for (int i = 0; i < matrix.Rows; i++)
            {
                matrix.SetRow(i, vector);
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(array[j], matrix[i, j]);
                }
            }

            matrix = GetMatrix(wide);
            array = new double[] { 1, 2, 3 };
            vector = GetVector(array);
            for (int i = 0; i < matrix.Rows; i++)
            {
                matrix.SetRow(i, vector);
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(array[j], matrix[i, j]);
                }
            }

            matrix = GetMatrix(tall);
            array = new double[] { 1, 2 };
            vector = GetVector(array);
            for (int i = 0; i < matrix.Rows; i++)
            {
                matrix.SetRow(i, vector);
                for (int j = 0; j < array.Length; j++)
                {
                    Assert.AreEqual(array[j], matrix[i, j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SetRowVectorNull()
        {
            Matrix matrix = GetMatrix(square);
            Vector vector = null;
            matrix.SetRow(0, vector);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SetRowVectorArgumentOutOfRange1()
        {
            Matrix matrix = GetMatrix(square);
            double[] array = new double[] { 1, 2, 3 };
            Vector vector = GetVector(array);
            matrix.SetRow(-1, vector);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SetRowVectorArgumentOutOfRange2()
        {
            Matrix matrix = GetMatrix(square);
            double[] array = new double[] { 1, 2, 3 };
            Vector vector = GetVector(array);
            matrix.SetRow(matrix.Rows + 1, vector);
        }

        [Test]
        public void SetRowArray()
        {
            Matrix matrix = GetMatrix(square);
            double[] array = new double[] { 1, 2, 3 };
            for (int i = 0; i < matrix.Rows; i++)
            {
                matrix.SetRow(i, array);
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(array[j], matrix[i, j]);
                }
            }

            matrix = GetMatrix(wide);
            array = new double[] { 1, 2, 3 };
            for (int i = 0; i < matrix.Rows; i++)
            {
                matrix.SetRow(i, array);
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(array[j], matrix[i, j]);
                }
            }

            matrix = GetMatrix(tall);
            array = new double[] { 1, 2 };
            for (int i = 0; i < matrix.Rows; i++)
            {
                matrix.SetRow(i, array);
                for (int j = 0; j < array.Length; j++)
                {
                    Assert.AreEqual(array[j], matrix[i, j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SetRowArrayNull()
        {
            Matrix matrix = GetMatrix(square);
            double[] array = null;
            matrix.SetRow(0, array);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SetRowArrayArgumentOutOfRange1()
        {
            Matrix matrix = GetMatrix(square);
            double[] array = new double[] { 1, 2, 3 };
            matrix.SetRow(-1, array);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SetRowArrayArgumentOutOfRange2()
        {
            Matrix matrix = GetMatrix(square);
            double[] array = new double[] { 1, 2, 3 };
            matrix.SetRow(matrix.Rows + 1, array);
        }

        [Test]
        public void SetDiagonalVector()
        {
            Matrix matrix = GetMatrix(square);
            double[] array = new double[] { 1, 2, 3 };
            Vector vector = GetVector(array);
            matrix.SetDiagonal(vector);

            for (int i = 0; i < array.Length; i++)
            {
                Assert.AreEqual(array[i], matrix[i, i]);
            }

            matrix = GetMatrix(wide);
            array = new double[] { 1, 2 };
            vector = GetVector(array);
            matrix.SetDiagonal(vector);
            for (int i = 0; i < array.Length; i++)
            {
                Assert.AreEqual(array[i], matrix[i, i]);
            }

            matrix = GetMatrix(tall);
            array = new double[] { 1, 2 };
            vector = GetVector(array);
            matrix.SetDiagonal(vector);
            for (int i = 0; i < array.Length; i++)
            {
                Assert.AreEqual(array[i], matrix[i, i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SetDiagonalVectorNull()
        {
            Matrix matrix = GetMatrix(square);
            Vector vector = null;
            matrix.SetDiagonal(vector);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void SetDiagonalVectorNotConformable()
        {
            Matrix matrix = GetMatrix(square);
            Vector vector = GetVector(matrix.Rows + 1);
            matrix.SetDiagonal(vector);
        }

        [Test]
        public void SetDiagonalArray()
        {
            Matrix matrix = GetMatrix(square);
            double[] array = new double[] { 1, 2, 3 };
            matrix.SetDiagonal(array);

            for (int i = 0; i < array.Length; i++)
            {
                Assert.AreEqual(array[i], matrix[i, i]);
            }

            matrix = GetMatrix(wide);
            array = new double[] { 1, 2 };
            matrix.SetDiagonal(array);
            for (int i = 0; i < array.Length; i++)
            {
                Assert.AreEqual(array[i], matrix[i, i]);
            }

            matrix = GetMatrix(tall);
            array = new double[] { 1, 2 };
            matrix.SetDiagonal(array);
            for (int i = 0; i < array.Length; i++)
            {
                Assert.AreEqual(array[i], matrix[i, i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SetDiagonalArrayNull()
        {
            Matrix matrix = GetMatrix(square);
            double[] array = null;
            matrix.SetDiagonal(array);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void SetDiagonalArrayNotConformable()
        {
            Matrix matrix = GetMatrix(square);
            double[] array = new double[matrix.Rows + 1];
            matrix.SetDiagonal(array);
        }

        [Test]
        public void Stack()
        {
            Matrix top = GetMatrix(square);
            Matrix bottom = GetMatrix(wide);
            Matrix result = top.Stack(bottom);
            Assert.AreEqual(top.Rows + bottom.Rows, result.Rows);
            Assert.AreEqual(top.Columns, result.Columns);

            for (int i = 0; i < result.Rows; i++)
            {
                for (int j = 0; j < result.Columns; j++)
                {
                    if (i < top.Rows)
                    {
                        Assert.AreEqual(top[i, j], result[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(bottom[i - top.Rows, j], result[i, j]);
                    }
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void StackNull()
        {
            Matrix top = GetMatrix(square);
            Matrix bottom = null;
            Matrix result = top.Stack(bottom);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void StackNotConformable()
        {
            Matrix top = GetMatrix(wide);
            Matrix bottom = GetMatrix(tall);
            Matrix result = top.Stack(bottom);
        }

        [Test]
        public void StackResult()
        {
            Matrix top = GetMatrix(square);
            Matrix bottom = GetMatrix(wide);
            Matrix result = GetMatrix(top.Rows + bottom.Rows, top.Columns);
            top.Stack(bottom, result);
            Assert.AreEqual(top.Rows + bottom.Rows, result.Rows);
            Assert.AreEqual(top.Columns, result.Columns);

            for (int i = 0; i < result.Rows; i++)
            {
                for (int j = 0; j < result.Columns; j++)
                {
                    if (i < top.Rows)
                    {
                        Assert.AreEqual(top[i, j], result[i, j]);
                    }
                    else
                    {
                        Assert.AreEqual(bottom[i - top.Rows, j], result[i, j]);
                    }
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void StackResultNull1()
        {
            Matrix top = GetMatrix(square);
            Matrix bottom = null;
            Matrix result = GetMatrix(top.Rows + top.Rows, top.Columns);
            top.Stack(bottom, result);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void StackResultNull2()
        {
            Matrix top = GetMatrix(square);
            Matrix bottom = GetMatrix(wide);
            Matrix result = null;
            top.Stack(bottom, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void StackResultNotConformable1()
        {
            Matrix top = GetMatrix(wide);
            Matrix bottom = GetMatrix(tall);
            Matrix result = GetMatrix(top.Rows + bottom.Rows, top.Columns);
            top.Stack(bottom, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void StackResultNotConformable2()
        {
            Matrix top = GetMatrix(wide);
            Matrix bottom = GetMatrix(wide);
            Matrix result = GetMatrix(top.Rows + bottom.Rows + 1, top.Columns);
            top.Stack(bottom, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void StackResultNotConformable3()
        {
            Matrix top = GetMatrix(wide);
            Matrix bottom = GetMatrix(wide);
            Matrix result = GetMatrix(top.Rows + bottom.Rows, top.Columns + 1);
            top.Stack(bottom, result);
        }

        [Test]
        public void SubMatrix()
        {
            Matrix matrix = GetMatrix(square);
            Range rowRange = new Range(0, matrix.Rows - 1, 2);
            Range colRange = new Range(0, matrix.Columns - 1, 2);
            Matrix subMatrix = matrix.SubMatrix(rowRange, colRange);

            int m = (rowRange.End - rowRange.Start) / rowRange.Stride + 1;
            int n = (colRange.End - colRange.Start) / colRange.Stride + 1;
            Assert.AreEqual(m, subMatrix.Rows);
            Assert.AreEqual(n, subMatrix.Columns);
            for (int i = rowRange.Start, ii = 0; i <= rowRange.End; i += rowRange.Stride, ii++)
            {
                for (int j = colRange.Start, jj = 0; j <= colRange.End; j += colRange.Stride, jj++)
                {
                    Assert.AreEqual(matrix[i, j], subMatrix[ii, jj]);
                }
            }

            matrix = GetMatrix(wide);
            rowRange = new Range(0, matrix.Rows - 1, 2);
            colRange = new Range(0, matrix.Columns - 1, 2);
            subMatrix = matrix.SubMatrix(rowRange, colRange);
            m = (rowRange.End - rowRange.Start) / rowRange.Stride + 1;
            n = (colRange.End - colRange.Start) / colRange.Stride + 1;
            Assert.AreEqual(m, subMatrix.Rows);
            Assert.AreEqual(n, subMatrix.Columns);
            for (int i = rowRange.Start, ii = 0; i <= rowRange.End; i += rowRange.Stride, ii++)
            {
                for (int j = colRange.Start, jj = 0; j <= colRange.End; j += colRange.Stride, jj++)
                {
                    Assert.AreEqual(matrix[i, j], subMatrix[ii, jj]);
                }
            }

            matrix = GetMatrix(tall);
            rowRange = new Range(0, matrix.Rows - 1, 2);
            colRange = new Range(0, matrix.Columns - 1, 2);
            subMatrix = matrix.SubMatrix(rowRange, colRange);
            m = (rowRange.End - rowRange.Start) / rowRange.Stride + 1;
            n = (colRange.End - colRange.Start) / colRange.Stride + 1;
            Assert.AreEqual(m, subMatrix.Rows);
            Assert.AreEqual(n, subMatrix.Columns);
            for (int i = rowRange.Start, ii = 0; i <= rowRange.End; i += rowRange.Stride, ii++)
            {
                for (int j = colRange.Start, jj = 0; j <= colRange.End; j += colRange.Stride, jj++)
                {
                    Assert.AreEqual(matrix[i, j], subMatrix[ii, jj]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SubMatrixArgumentOutOfRange1()
        {
            Matrix matrix = GetMatrix(square);
            Range rowRange = new Range(matrix.Rows, matrix.Rows + 1, 2);
            Range colRange = new Range(0, matrix.Columns - 1, 2);
            Matrix subMatrix = matrix.SubMatrix(rowRange, colRange);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SubMatrixArgumentOutOfRange2()
        {
            Matrix matrix = GetMatrix(square);
            Range rowRange = new Range(0, matrix.Rows, 2);
            Range colRange = new Range(0, matrix.Columns - 1, 2);
            Matrix subMatrix = matrix.SubMatrix(rowRange, colRange);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SubMatrixArgumentOutOfRange3()
        {
            Matrix matrix = GetMatrix(square);
            Range rowRange = new Range(0, matrix.Rows - 1, 2);
            Range colRange = new Range(matrix.Columns, matrix.Columns + 1, 2);
            Matrix subMatrix = matrix.SubMatrix(rowRange, colRange);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SubMatrixArgumentOutOfRange4()
        {
            Matrix matrix = GetMatrix(square);
            Range rowRange = new Range(0, matrix.Rows - 1, 2);
            Range colRange = new Range(0, matrix.Columns, 2);
            Matrix subMatrix = matrix.SubMatrix(rowRange, colRange);
        }

        [Test]
        public void SubMatrixResult()
        {
            Matrix matrix = GetMatrix(square);
            Range rowRange = new Range(0, matrix.Rows - 1, 2);
            Range colRange = new Range(0, matrix.Columns - 1, 2);
            int m = (rowRange.End - rowRange.Start) / rowRange.Stride + 1;
            int n = (colRange.End - colRange.Start) / colRange.Stride + 1;
            Matrix subMatrix = GetMatrix(m, n);
            matrix.SubMatrix(rowRange, colRange, subMatrix);
            Assert.AreEqual(m, subMatrix.Rows);
            Assert.AreEqual(n, subMatrix.Columns);
            for (int i = rowRange.Start, ii = 0; i <= rowRange.End; i += rowRange.Stride, ii++)
            {
                for (int j = colRange.Start, jj = 0; j <= colRange.End; j += colRange.Stride, jj++)
                {
                    Assert.AreEqual(matrix[i, j], subMatrix[ii, jj]);
                }
            }

            matrix = GetMatrix(wide);
            rowRange = new Range(0, matrix.Rows - 1, 2);
            colRange = new Range(0, matrix.Columns - 1, 2);
            m = (rowRange.End - rowRange.Start) / rowRange.Stride + 1;
            n = (colRange.End - colRange.Start) / colRange.Stride + 1;
            subMatrix = GetMatrix(m, n);
            matrix.SubMatrix(rowRange, colRange, subMatrix);
            Assert.AreEqual(m, subMatrix.Rows);
            Assert.AreEqual(n, subMatrix.Columns);
            for (int i = rowRange.Start, ii = 0; i <= rowRange.End; i += rowRange.Stride, ii++)
            {
                for (int j = colRange.Start, jj = 0; j <= colRange.End; j += colRange.Stride, jj++)
                {
                    Assert.AreEqual(matrix[i, j], subMatrix[ii, jj]);
                }
            }

            matrix = GetMatrix(tall);
            rowRange = new Range(0, matrix.Rows - 1, 2);
            colRange = new Range(0, matrix.Columns - 1, 2);
            m = (rowRange.End - rowRange.Start) / rowRange.Stride + 1;
            n = (colRange.End - colRange.Start) / colRange.Stride + 1;
            subMatrix = GetMatrix(m, n);
            matrix.SubMatrix(rowRange, colRange, subMatrix);
            Assert.AreEqual(m, subMatrix.Rows);
            Assert.AreEqual(n, subMatrix.Columns);
            for (int i = rowRange.Start, ii = 0; i <= rowRange.End; i += rowRange.Stride, ii++)
            {
                for (int j = colRange.Start, jj = 0; j <= colRange.End; j += colRange.Stride, jj++)
                {
                    Assert.AreEqual(matrix[i, j], subMatrix[ii, jj]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SubMatrixResultArgumentOutOfRangeException1()
        {
            Matrix matrix = GetMatrix(square);
            Range rowRange = new Range(matrix.Rows, matrix.Rows + 1, 2);
            Range colRange = new Range(0, matrix.Columns - 1, 2);
            int m = (rowRange.End - rowRange.Start) / rowRange.Stride + 1;
            int n = (colRange.End - colRange.Start) / colRange.Stride + 1;
            Matrix subMatrix = GetMatrix(m, n);
            matrix.SubMatrix(rowRange, colRange, subMatrix);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SubMatrixResultArgumentOutOfRangeException2()
        {
            Matrix matrix = GetMatrix(square);
            Range rowRange = new Range(0, matrix.Rows, 2);
            Range colRange = new Range(0, matrix.Columns - 1, 2);
            int m = (rowRange.End - rowRange.Start) / rowRange.Stride + 1;
            int n = (colRange.End - colRange.Start) / colRange.Stride + 1;
            Matrix subMatrix = GetMatrix(m, n);
            matrix.SubMatrix(rowRange, colRange, subMatrix);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SubMatrixResultArgumentOutOfRangeException3()
        {
            Matrix matrix = GetMatrix(square);
            Range rowRange = new Range(0, matrix.Rows - 1, 2);
            Range colRange = new Range(matrix.Columns, matrix.Columns + 1, 2);
            int m = (rowRange.End - rowRange.Start) / rowRange.Stride + 1;
            int n = (colRange.End - colRange.Start) / colRange.Stride + 1;
            Matrix subMatrix = GetMatrix(m, n);
            matrix.SubMatrix(rowRange, colRange, subMatrix);
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SubMatrixResultArgumentOutOfRangeException4()
        {
            Matrix matrix = GetMatrix(square);
            Range rowRange = new Range(0, matrix.Rows - 1, 2);
            Range colRange = new Range(0, matrix.Columns, 2);
            int m = (rowRange.End - rowRange.Start) / rowRange.Stride + 1;
            int n = (colRange.End - colRange.Start) / colRange.Stride + 1;
            Matrix subMatrix = GetMatrix(m, n);
            matrix.SubMatrix(rowRange, colRange, subMatrix);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SubMatrixResultArgumentNullException()
        {
            Matrix matrix = GetMatrix(square);
            Range rowRange = new Range(0, matrix.Rows - 1, 2);
            Range colRange = new Range(0, matrix.Columns - 1, 2);
            Matrix subMatrix = null;
            matrix.SubMatrix(rowRange, colRange, subMatrix);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void SubMatrixResultNotConformableException1()
        {
            Matrix matrix = GetMatrix(square);
            Range rowRange = new Range(0, matrix.Rows - 1, 2);
            Range colRange = new Range(0, matrix.Columns - 1, 2);
            Matrix subMatrix = GetMatrix(matrix.Rows, (colRange.End - colRange.Start) / colRange.Stride + 1);
            matrix.SubMatrix(rowRange, colRange, subMatrix);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void SubMatrixResultNotConformableException2()
        {
            Matrix matrix = GetMatrix(square);
            Range rowRange = new Range(0, matrix.Rows - 1, 2);
            Range colRange = new Range(0, matrix.Columns - 1, 2);
            Matrix subMatrix = GetMatrix((rowRange.End - rowRange.Start) / rowRange.Stride + 1, matrix.Columns);
            matrix.SubMatrix(rowRange, colRange, subMatrix);
        }

        [Test]
        public void SetSubMatrix()
        {
            Matrix matrix = GetMatrix(square);
            Range rowRange = new Range(0, matrix.Rows - 2);
            Range colRange = new Range(0, matrix.Columns - 2);
            Matrix sub = matrix.SubMatrix(rowRange, colRange);
            matrix.SetSubMatrix(1, 1, sub);

            for (int i = 1; i < matrix.Rows; i++)
            {
                for (int j = 1; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i - 1, j - 1], matrix[i, j]);
                }
            }

            matrix = GetMatrix(wide);
            rowRange = new Range(0, matrix.Rows - 2);
            colRange = new Range(0, matrix.Columns - 2);
            sub = matrix.SubMatrix(rowRange, colRange);
            matrix.SetSubMatrix(1, 1, sub);
            for (int i = 1; i < matrix.Rows; i++)
            {
                for (int j = 1; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i - 1, j - 1], matrix[i, j]);
                }
            }

            matrix = GetMatrix(tall);
            rowRange = new Range(0, matrix.Rows - 2);
            colRange = new Range(0, matrix.Columns - 2);
            sub = matrix.SubMatrix(rowRange, colRange);
            matrix.SetSubMatrix(1, 1, sub);
            for (int i = 1; i < matrix.Rows; i++)
            {
                for (int j = 1; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i - 1, j - 1], matrix[i, j]);
                }
            }
        }

        [Test]
        public void SubtractScalar()
        {
            Matrix matrix = GetMatrix(square);
            matrix.Subtract(2.2);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] - 2.2, matrix[i, j]);
                }
            }

            matrix = GetMatrix(wide);
            matrix.Subtract(2.2);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] - 2.2, matrix[i, j]);
                }
            }

            matrix = GetMatrix(tall);
            matrix.Subtract(2.2);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] - 2.2, matrix[i, j]);
                }
            }
        }

        [Test]
        public void SubtractScalarResult()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Subtract(2.2, result);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] - 2.2, result[i, j]);
                }
            }

            matrix = GetMatrix(wide);
            result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Subtract(2.2, result);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] - 2.2, result[i, j]);
                }
            }

            matrix = GetMatrix(tall);
            result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Subtract(2.2, result);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] - 2.2, result[i, j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SubtractScalarResultNull()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = null;
            matrix.Subtract(2.2, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void SubtractScalarResultNotConformable1()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = GetMatrix(matrix.Rows + 1, matrix.Columns);
            matrix.Subtract(2.2, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void SubtractScalarResultNotConformable2()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = GetMatrix(matrix.Rows, matrix.Columns + 1);
            matrix.Subtract(2.2, result);
        }

        [Test]
        public void SubtractMatrix()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = matrix.Clone();
            matrix.Subtract(other);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] - square[i, j], matrix[i, j]);
                }
            }

            matrix = GetMatrix(wide);
            other = matrix.Clone();
            matrix.Subtract(other);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(wide[i, j] - wide[i, j], matrix[i, j]);
                }
            }

            matrix = GetMatrix(tall);
            other = matrix.Clone();
            matrix.Subtract(other);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(tall[i, j] - tall[i, j], matrix[i, j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SubtractMatrixNull()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = null;
            matrix.Subtract(other);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void SubtractMatrixNotConformable1()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = GetMatrix(matrix.Rows + 1, matrix.Columns);
            matrix.Subtract(other);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void SubtractMatrixNotConformable2()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = GetMatrix(matrix.Rows, matrix.Columns + 1);
            matrix.Subtract(other);
        }

        [Test]
        public void SubtractMatrixResult()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = matrix.Clone();
            Matrix result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Subtract(other, result);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] - square[i, j], result[i, j]);
                }
            }

            matrix = GetMatrix(wide);
            other = matrix.Clone();
            result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Subtract(other, result);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(wide[i, j] - wide[i, j], result[i, j]);
                }
            }

            matrix = GetMatrix(tall);
            other = matrix.Clone();
            result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Subtract(other, result);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(tall[i, j] - tall[i, j], result[i, j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SubtractMatrixResultNull1()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = null;
            Matrix result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Subtract(other, result);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SubtractMatrixResultNull2()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = matrix.Clone();
            Matrix result = null;
            matrix.Subtract(other, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void SubtractMatrixResultNotConformable1()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = GetMatrix(matrix.Rows + 1, matrix.Columns);
            Matrix result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Subtract(other, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void SubtractMatrixResultNotConformable2()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = GetMatrix(matrix.Rows, matrix.Columns + 1);
            Matrix result = GetMatrix(matrix.Rows, matrix.Columns);
            matrix.Subtract(other, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void SubtractMatrixResultNotConformable3()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = GetMatrix(matrix.Rows, matrix.Columns);
            Matrix result = GetMatrix(matrix.Rows + 1, matrix.Columns);
            matrix.Subtract(other, result);
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void SubtractMatrixResultNotConformable4()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = GetMatrix(matrix.Rows, matrix.Columns);
            Matrix result = GetMatrix(matrix.Rows, matrix.Columns + 1);
            matrix.Subtract(other, result);
        }
        [Test]
        public void Indexer()
        {
            Matrix matrix = GetMatrix(m, n);
            for (int i = 0; i < m; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    matrix[i, j] = i + j;
                    Assert.AreEqual(i + j, matrix[i, j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void IndexerGetterArgumentOutOfRange1()
        {
            Matrix matrix = GetMatrix(m, n);
            double temp = matrix[-1, 0];
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void IndexerGetterArgumentOutOfRange2()
        {
            Matrix matrix = GetMatrix(m, n);
            double temp = matrix[0, -1];
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void IndexerGetterArgumentOutOfRange3()
        {
            Matrix matrix = GetMatrix(m, n);
            double temp = matrix[m, 0];
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void IndexerGetterArgumentOutOfRange4()
        {
            Matrix matrix = GetMatrix(m, n);
            double temp = matrix[0, n];
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void IndexerSetterArgumentOutOfRange1()
        {
            Matrix matrix = GetMatrix(m, n);
            matrix[-1, 0] = 1;
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void IndexerSetterArgumentOutOfRange2()
        {
            Matrix matrix = GetMatrix(m, n);
            matrix[0, -1] = 1;
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void IndexerSetterArgumentOutOfRange3()
        {
            Matrix matrix = GetMatrix(m, n);
            matrix[m, 0] = 1;
        }

        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void IndexerSetterArgumentOutOfRange4()
        {
            Matrix matrix = GetMatrix(m, n);
            matrix[0, n] = 1;
        }

        [Test]
        public void ValueAt()
        {
            Matrix matrix = GetMatrix(m, n);
            for (int i = 0; i < m; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    matrix.ValueAt(i, j, (i + j));
                    Assert.AreEqual(i + j, matrix.ValueAt(i, j));
                }
            }
        }

        [Test]
        public void ToArray()
        {
            Matrix matrix = GetMatrix(square);
            double[,] array = matrix.ToArray();
            Assert.AreEqual(matrix.Rows, array.GetLength(0));
            Assert.AreEqual(matrix.Columns, array.GetLength(1));

            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], array[i, j]);
                }
            }

            matrix = GetMatrix(wide);
            array = matrix.ToArray();
            Assert.AreEqual(matrix.Rows, array.GetLength(0));
            Assert.AreEqual(matrix.Columns, array.GetLength(1));

            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], array[i, j]);
                }
            }

            matrix = GetMatrix(tall);
            array = matrix.ToArray();
            Assert.AreEqual(matrix.Rows, array.GetLength(0));
            Assert.AreEqual(matrix.Columns, array.GetLength(1));

            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], array[i, j]);
                }
            }
        }

        [Test]
        public void ToColumnWiseArray()
        {
            Matrix matrix = GetMatrix(square);
            double[] array = matrix.ToColumnWiseArray();
            Assert.AreEqual(matrix.Rows * matrix.Columns, array.Length);

            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], array[j * matrix.Rows + i]);
                }
            }

            matrix = GetMatrix(wide);
            array = matrix.ToColumnWiseArray();
            Assert.AreEqual(matrix.Rows * matrix.Columns, array.Length);

            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], array[j * matrix.Rows + i]);
                }
            }

            matrix = GetMatrix(tall);
            array = matrix.ToColumnWiseArray();
            Assert.AreEqual(matrix.Rows * matrix.Columns, array.Length);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], array[j * matrix.Rows + i]);
                }
            }
        }

        [Test]
        public void ToRowWiseArray()
        {
            Matrix matrix = GetMatrix(square);
            double[] array = matrix.ToRowWiseArray();
            Assert.AreEqual(matrix.Rows * matrix.Columns, array.Length);

            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], array[i * matrix.Columns + j]);
                }
            }

            matrix = GetMatrix(wide);
            array = matrix.ToRowWiseArray();
            Assert.AreEqual(matrix.Rows * matrix.Columns, array.Length);

            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], array[i * matrix.Columns + j]);
                }
            }

            matrix = GetMatrix(tall);
            array = matrix.ToRowWiseArray();
            Assert.AreEqual(matrix.Rows * matrix.Columns, array.Length);
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], array[i * matrix.Columns + j]);
                }
            }
        }

        [Test]
        public void OperatorPlus()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = +matrix;
            Assert.IsFalse(Object.ReferenceEquals(matrix, result));
            Assert.AreEqual(matrix.Rows, result.Rows);
            Assert.AreEqual(matrix.Columns, result.Columns);
            for (int i = 0; i < result.Rows; i++)
            {
                for (int j = 0; j < result.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], result[i, j]);
                }
            }

            matrix = GetMatrix(wide);
            result = +matrix;
            Assert.IsFalse(Object.ReferenceEquals(matrix, result));
            Assert.AreEqual(matrix.Rows, result.Rows);
            Assert.AreEqual(matrix.Columns, result.Columns);
            for (int i = 0; i < result.Rows; i++)
            {
                for (int j = 0; j < result.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], result[i, j]);
                }
            }

            matrix = GetMatrix(tall);
            result = +matrix;
            Assert.IsFalse(Object.ReferenceEquals(matrix, result));
            Assert.AreEqual(matrix.Rows, result.Rows);
            Assert.AreEqual(matrix.Columns, result.Columns);
            for (int i = 0; i < result.Rows; i++)
            {
                for (int j = 0; j < result.Columns; j++)
                {
                    Assert.AreEqual(matrix[i, j], result[i, j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorPlusNull()
        {
            Matrix matrix = null;
            Matrix result = +matrix;
        }

        [Test]
        public void OperatorAddMatrixMatrix()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = GetMatrix(square);
            Matrix result = matrix + other;
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] + square[i, j], result[i, j]);
                }
            }

            matrix = GetMatrix(wide);
            other = GetMatrix(wide);
            result = matrix + other;
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(wide[i, j] + wide[i, j], result[i, j]);
                }
            }

            matrix = GetMatrix(tall);
            other = GetMatrix(tall);
            result = matrix + other;
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(tall[i, j] + tall[i, j], result[i, j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorAddMatrixNullMatrix()
        {
            Matrix matrix = null;
            Matrix other = GetMatrix(square);
            Matrix result = matrix + other;
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorAddMatrixMatrixNull()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = null;
            Matrix result = matrix + other;
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void OperatorAddMatrixMatrixNotConformable1()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = GetMatrix(wide);
            Matrix result = matrix + other;
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void OperatorAddMatrixMatrixNotConformable2()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = GetMatrix(tall);
            Matrix result = matrix + other;
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void OperatorAddMatrixMatrixNotConformable3()
        {
            Matrix matrix = GetMatrix(wide);
            Matrix other = GetMatrix(tall);
            Matrix result = matrix + other;
        }

        [Test]
        public void OperatorNegate()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = -matrix;
            Assert.IsFalse(Object.ReferenceEquals(matrix, result));
            Assert.AreEqual(matrix.Rows, result.Rows);
            Assert.AreEqual(matrix.Columns, result.Columns);
            for (int i = 0; i < result.Rows; i++)
            {
                for (int j = 0; j < result.Columns; j++)
                {
                    Assert.AreEqual(-matrix[i, j], result[i, j]);
                }
            }

            matrix = GetMatrix(wide);
            result = -matrix;
            Assert.IsFalse(Object.ReferenceEquals(matrix, result));
            Assert.AreEqual(matrix.Rows, result.Rows);
            Assert.AreEqual(matrix.Columns, result.Columns);
            for (int i = 0; i < result.Rows; i++)
            {
                for (int j = 0; j < result.Columns; j++)
                {
                    Assert.AreEqual(-matrix[i, j], result[i, j]);
                }
            }

            matrix = GetMatrix(tall);
            result = -matrix;
            Assert.IsFalse(Object.ReferenceEquals(matrix, result));
            Assert.AreEqual(matrix.Rows, result.Rows);
            Assert.AreEqual(matrix.Columns, result.Columns);
            for (int i = 0; i < result.Rows; i++)
            {
                for (int j = 0; j < result.Columns; j++)
                {
                    Assert.AreEqual(-matrix[i, j], result[i, j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorNegateNull()
        {
            Matrix matrix = null;
            Matrix result = -matrix;
        }

        [Test]
        public void OperatorSubtractMatrixMatrix()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = matrix.Clone();
            Matrix result = matrix - other;
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] - square[i, j], result[i, j]);
                }
            }

            matrix = GetMatrix(wide);
            other = matrix.Clone();
            result = matrix - other;
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(wide[i, j] - wide[i, j], result[i, j]);
                }
            }

            matrix = GetMatrix(tall);
            other = matrix.Clone();
            result = matrix - other;
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(tall[i, j] - tall[i, j], result[i, j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorSubtractMatrixNullMatrix()
        {
            Matrix matrix = null;
            Matrix other = GetMatrix(square);
            Matrix result = matrix - other;
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorSubtractMatrixMatrixNull()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = null;
            Matrix result = matrix - other;
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void OperatorSubtractMatrixMatrixNotConformable1()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = GetMatrix(wide);
            Matrix result = matrix - other;
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void OperatorSubtractMatrixMatrixNotConformable2()
        {
            Matrix matrix = GetMatrix(square);
            Matrix other = GetMatrix(tall);
            Matrix result = matrix - other;
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void OperatorSubtractMatrixMatrixNotConformable3()
        {
            Matrix matrix = GetMatrix(wide);
            Matrix other = GetMatrix(tall);
            Matrix result = matrix - other;
        }

        [Test]
        public void OperatorDivide()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = matrix / .1234;
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] / .1234, result[i, j], Constants.ACCEPTABLE_ERROR);
                }
            }

            matrix = GetMatrix(wide);
            result = matrix / .1234;
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(wide[i, j] / .1234, result[i, j], Constants.ACCEPTABLE_ERROR);
                }
            }

            matrix = GetMatrix(tall);
            result = matrix / .1234;
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(tall[i, j] / .1234, result[i, j], Constants.ACCEPTABLE_ERROR);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorDivideNull()
        {
            Matrix matrix = null;
            Matrix result = matrix / .1234;
        }

        [Test]
        public void OperatorMultiplyMatrixScalar()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = matrix * .1234;
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] * .1234, result[i, j], Constants.ACCEPTABLE_ERROR);
                }
            }

            matrix = GetMatrix(wide);
            result = matrix * .1234;
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(wide[i, j] * .1234, result[i, j], Constants.ACCEPTABLE_ERROR);
                }
            }

            matrix = GetMatrix(tall);
            result = matrix * .1234;
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(tall[i, j] * .1234, result[i, j], Constants.ACCEPTABLE_ERROR);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorMultiplyMatrixScalarNull()
        {
            Matrix matrix = null;
            Matrix result = matrix * .1234;
        }

        [Test]
        public void OperatorMultiplyScalarMatrix()
        {
            Matrix matrix = GetMatrix(square);
            Matrix result = .1234 * matrix;
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(square[i, j] * .1234, result[i, j], Constants.ACCEPTABLE_ERROR);
                }
            }

            matrix = GetMatrix(wide);
            result = .1234 * matrix;
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(wide[i, j] * .1234, result[i, j], Constants.ACCEPTABLE_ERROR);
                }
            }

            matrix = GetMatrix(tall);
            result = .1234 * matrix;
            for (int i = 0; i < matrix.Rows; i++)
            {
                for (int j = 0; j < matrix.Columns; j++)
                {
                    Assert.AreEqual(tall[i, j] * .1234, result[i, j], Constants.ACCEPTABLE_ERROR);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorMultiplyScalarMatrixNull()
        {
            Matrix matrix = null;
            Matrix result = .1234 * matrix;
        }

        [Test]
        public void OperatorMultiplyMatrixMatrix()
        {
            Matrix matrix1 = GetMatrix(square);
            Matrix matrix2 = GetMatrix(square);
            Matrix result = matrix1 * matrix2;

            Assert.AreEqual(3, result.Rows);
            Assert.AreEqual(3, result.Columns);
            Assert.AreEqual(15.73, result[0, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(-18.15, result[0, 1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(-22.99, result[0, 2], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(-9.68, result[1, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(13.31, result[1, 1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(16.94, result[1, 2], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(-24.2, result[2, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(52.03, result[2, 1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(70.17999999999999, result[2, 2], Constants.ACCEPTABLE_ERROR);

            matrix1 = GetMatrix(wide);
            matrix2 = GetMatrix(tall);
            result = matrix1 * matrix2;

            Assert.AreEqual(2, result.Rows);
            Assert.AreEqual(2, result.Columns);
            Assert.AreEqual(15.73, result[0, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(-18.15, result[0, 1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(-9.68, result[1, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(13.31, result[1, 1], Constants.ACCEPTABLE_ERROR);

            matrix1 = GetMatrix(tall);
            matrix2 = GetMatrix(wide);
            result = matrix1 * matrix2;

            Assert.AreEqual(3, result.Rows);
            Assert.AreEqual(3, result.Columns);
            Assert.AreEqual(1.21, result[0, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(0, result[0, 1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(-1.21, result[0, 2], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(0, result[1, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(1.21, result[1, 1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(2.42, result[1, 2], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(4.84, result[2, 0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(15.73, result[2, 1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(26.62, result[2, 2], Constants.ACCEPTABLE_ERROR);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatotMulitplyMatrixNullMatrix()
        {
            Matrix matrix1 = null;
            Matrix matrix2 = GetMatrix(square);
            Matrix result = matrix1 * matrix2;
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatotMulitplyMatrixMatrixNull()
        {
            Matrix matrix1 = GetMatrix(square);
            Matrix matrix2 = null;
            Matrix result = matrix1 * matrix2;
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void OperatotMulitplyMatrixMatrixNotConformable()
        {
            Matrix matrix1 = GetMatrix(tall);
            Matrix matrix2 = GetMatrix(tall);
            Matrix result = matrix1 * matrix2;
        }

        [Test]
        public void OperatorMultiplyMatrixVector()
        {
            Matrix matrix = GetMatrix(square);
            Vector vector = GetVector(new double[] { 1.1, 2.2, 3.3 });
            Vector result = matrix * vector;
            Assert.AreEqual(matrix.Rows, result.Count);
            Assert.AreEqual(-16.94, result[0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(9.68, result[1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(29.04, result[2], Constants.ACCEPTABLE_ERROR);

            matrix = GetMatrix(wide);
            vector = GetVector(new double[] { 1.1, 2.2, 3.3 });
            result = matrix * vector;
            Assert.AreEqual(matrix.Rows, result.Count);
            Assert.AreEqual(-16.94, result[0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(9.68, result[1], Constants.ACCEPTABLE_ERROR);

            matrix = GetMatrix(tall);
            vector = GetVector(new double[] { 1.1, 2.2 });
            result = matrix * vector;
            Assert.AreEqual(matrix.Rows, result.Count);
            Assert.AreEqual(-6.05, result[0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(2.42, result[1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(7.26, result[2], Constants.ACCEPTABLE_ERROR);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorMultiplyMatrixNullVector()
        {
            Matrix matrix = null;
            Vector vector = GetVector(new double[] { 1.1, 2.2, 3.3 });
            Vector result = matrix * vector;
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorMultiplyMatrixVectorNull()
        {
            Matrix matrix = GetMatrix(square);
            Vector vector = null;
            Vector result = matrix * vector;
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void OperatorMultiplyMatrixVectorNotConformable()
        {
            Matrix matrix = GetMatrix(square);
            Vector vector = GetVector(new double[] { 1.1, 2.2 });
            Vector result = matrix * vector;
        }

        [Test]
        public void OperatorMultiplyVectorMatrix()
        {
            Matrix matrix = GetMatrix(square);
            Vector vector = GetVector(new double[] { 1.1, 2.2, 3.3 });
            Vector result = vector * matrix;
            Assert.AreEqual(matrix.Columns, result.Count);
            Assert.AreEqual(-15.73, result[0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(18.15, result[1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(22.99, result[2], Constants.ACCEPTABLE_ERROR);

            matrix = GetMatrix(wide);
            vector = GetVector(new double[] { 1.1, 2.2 });
            result = vector * matrix;
            Assert.AreEqual(matrix.Columns, result.Count);
            Assert.AreEqual(-1.21, result[0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(0, result[1], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(1.21, result[2], Constants.ACCEPTABLE_ERROR);

            matrix = GetMatrix(tall);
            vector = GetVector(new double[] { 1.1, 2.2, 3.3 });
            result = vector * matrix;
            Assert.AreEqual(matrix.Columns, result.Count);
            Assert.AreEqual(-15.73, result[0], Constants.ACCEPTABLE_ERROR);
            Assert.AreEqual(18.15, result[1], Constants.ACCEPTABLE_ERROR);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorMultiplyVectorMatrixNull()
        {
            Matrix matrix = null;
            Vector vector = GetVector(new double[] { 1.1, 2.2, 3.3 });
            Vector result = vector * matrix;
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void OperatorMultiplyVectorNullMatrix()
        {
            Matrix matrix = GetMatrix(square);
            Vector vector = null;
            Vector result = vector * matrix;
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void OperatorMultiplyVectorMatrixNotConformable()
        {
            Matrix matrix = GetMatrix(square);
            Vector vector = GetVector(new double[] { 1.1, 2.2 });
            Vector result = vector * matrix;
        }
    }
}
